from core.models.Model import Model
from dataclasses import dataclass, field
from dataclasses_json import config, Exclude
from typing import Optional

_table_name: str = 'applications'

_table_definition: str = """
    'id' int UNIQUE,
    'code' varchar UNIQUE,
    'name' varchar UNIQUE
"""


@dataclass
class Application(Model):
    code: str
    name: Optional[str] = field(
        default=None,
        metadata=config(exclude=Exclude.ALWAYS)
    )
    id: Optional[int] = field(
        default=None,
        metadata=config(exclude=Exclude.ALWAYS)
    )

    @staticmethod
    def find_by_id(id: int):
        Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition)
        return Model._query_one('SELECT * FROM applications WHERE id = ? LIMIT 1', Application.factory, [id])

    @staticmethod
    def find(code: str):
        Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition)
        return Model._query_one('SELECT * FROM applications WHERE code = ? LIMIT 1', Application.factory, [code])

    @staticmethod
    def truncate():
        Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition, drop_existing=True)

    @staticmethod
    def save_many(applications):
        Model._create_table_if_not_exists(table_name=_table_name, table_definition=_table_definition)
        Model._insert_many('INSERT INTO applications VALUES(?, ?, ?)', Application.tuple_factory, applications)

    @staticmethod
    def factory(cursor, row):
        database_fields = [column[0] for column in cursor.description]
        return Application(**{key: value for key, value in zip(database_fields, row)})

    @staticmethod
    def tuple_factory(application):
        return application.id, application.code, application.name