from sqlite3 import Connection
from typing import (
    List,
    Optional,
)

from boss.model import User
from boss.model.repository import UserRepository
from dbapitemplate import DbApiTemplate


class UserRepositoryImpl(UserRepository):

    _mandatory_user_fields = [
        "user_id",
        "user_name",
        "long_name",
        "password",
        "level",
        "status",
        "admission_date",
    ]

    def __init__(
        self,
        connection: Connection,
    ) -> None:

        self.conn = DbApiTemplate(conn=connection)

        self.users_cache: List[User] = []

    def get_mandatory_user_fields(
        self,
    ) -> List[str]:

        return self._mandatory_user_fields

    def get_user(
        self,
        user_id: int,
        passwords: List[str],
    ) -> Optional[User]:

        users = self.get_users_list()
        for user in users:
            if user.user_id == user_id and user.password in passwords:
                return user

        return None

    def get_user_by_id(
        self,
        user_id: int,
    ) -> Optional[User]:

        return next((user for user in self.get_users_list() if user.user_id == user_id), None)

    def get_user_by_nfc_uuid(
        self,
        nfc_uuid: str,
    ) -> Optional[User]:

        return next((user for user in self.get_users_list() if user.nfc_uuid == nfc_uuid), None)

    def get_users_list(
        self,
    ) -> List[User]:

        if not self.users_cache:
            self._update_users_cache()

        return self.users_cache

    def insert_or_update_users(
        self,
        users: List[User],
    ) -> None:

        params = []
        for user in users:

            params.append(
                (
                    user.user_id,
                    user.user_name,
                    user.long_name,
                    user.password,
                    user.level,
                    user.status,
                    user.admission_date,
                    user.termination_date,
                    user.fingerprint_minutiae,
                    user.nfc_uuid,
                )
            )

        query = """
            INSERT OR REPLACE INTO Users (
                UserId,
                UserName,
                LongName,
                Password,
                Level,
                Status,
                AdmissionDate,
                TerminationDate,
                FingerPrintMinutiae,
                NfcUuid
            )
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """

        self.conn.execute_many(
            sql=query,
            params=params,
        )

        self._update_users_cache()

    def _update_users_cache(
        self,
    ) -> None:

        self.users_cache = self.conn.execute(
            """
            SELECT
                UserId,
                UserName,
                LongName,
                Password,
                Level,
                Status,
                AdmissionDate,
                TerminationDate,
                FingerPrintMinutiae,
                NfcUuid
            FROM
                Users
        """,
            mapper=lambda x: User(
                user_id=x[0],
                user_name=x[1],
                long_name=x[2],
                password=x[3],
                level=x[4],
                status=x[5],
                admission_date=x[6],
                termination_date=x[7],
                fingerprint_minutiae=x[8],
                nfc_uuid=x[9],
            ),
        )
