"""This module contains utilities for creating fake database entries."""

from random import randint

from faker import Faker
from sqlalchemy.orm import Session

from todo.schemas.users import UserCreate, User
from todo.crud.users import create_user
from todo.schemas.todos import TodoItemCreate, TodoItem
from todo.crud.todos import create_todo
from todo.database.engine import get_db


def _get_faker() -> Faker:
    """Creates and returns a Faker object."""

    return Faker()


def get_fake_user_details() -> UserCreate:
    """Returns a set of fake details for creating a new user."""

    fk = _get_faker()

    password = fk.password(length=randint(6, 16))
    email = fk.profile(fields=['mail'])['mail']
    first_name = fk.first_name()
    last_name = fk.last_name()

    return UserCreate(
        email=email,
        first_name=first_name,
        last_name=last_name,
        password=password,
        password_confirmation=password,
    )


def get_fake_todo_details() -> TodoItemCreate:
    """Returns a set of fake details for creating a new todo-item."""

    fk = _get_faker()

    title = fk.sentence(nb_words=randint(4, 6))

    # Generate some sentences and concatenate them with a randomized delimiter
    description_sentences = [fk.sentence(nb_words=randint(4, 6)) for i in range(randint(1, 5))]
    if randint(0, 1):
        delimiter = '\n- '
    elif randint(0, 1):
        delimiter = '\n'
    else:
        delimiter = ' '
    description = delimiter.join(description_sentences)

    return TodoItemCreate(
        title=title,
        description=description,
    )


def create_fake_user(db: Session = next(get_db())) -> User:
    """Creates a fake user and saves them to the database."""

    return create_user(db=db, user=get_fake_user_details())


def create_fake_todo(user_id: int, db: Session = next(get_db())) -> TodoItem:
    """Creates a fake todo-item for the specified user and saves it to the database."""

    return create_todo(db=db, todo=get_fake_todo_details(), user_id=user_id)


def populate_database(num_users: int = 100, max_todos_per_user: int = 100) -> None:
    """Creates the specified number of users, each with between 0 and max_todos_per_user todo-items."""

    db = next(get_db())

    for i in range(num_users):
        user = create_fake_user(db)
        for j in range(randint(0, max_todos_per_user)):
            create_fake_todo(user.id, db)
