from datetime import datetime
from sqlalchemy import Column, DateTime, Integer, String, select
from db import Base, CRUD
import utils


class Patient(Base):
    __tablename__ = "patients"

    id = Column(Integer, primary_key=True, index=True)
    idPatientMis = Column(String, unique=True)
    familyName = Column(String)
    givenName = Column(String)
    middleName = Column(String)
    name = Column(String)
    fullName = Column(String)
    birthDate = Column(DateTime)
    sex = Column(String)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

    def toDict(self):
        return utils.toDict(self)

    async def save(self) -> "Patient":
        return await CRUD.create(self, refresh=True)

    async def edit(self, **kwargs) -> "Patient":
        return await CRUD.update(Patient, self.id, **kwargs)

    async def delete(self) -> bool:
        return await CRUD.delete(self)

    @staticmethod
    async def addPatient(**kwargs):

        idPatientMis = kwargs.get("idPatientMis", None)
        if not idPatientMis:
            utils.logger.error("Не указан идентификатор пациента")
            return utils.answer(
                success=False, message="Не указан идентификатор пациента"
            )
        if type(idPatientMis) != str:
            idPatientMis = str(idPatientMis)
            kwargs["idPatientMis"] = idPatientMis

        patient = await Patient.getPatientByIdPatientMis(
            idPatientMis=idPatientMis, toDict=False, isCheck=True
        )
        if patient.success:
            utils.logger.error(
                f"Пациент {patient.data.name} с идентификатором {idPatientMis} уже существует"
            )
            return utils.answer(
                success=False,
                message=f"Пациент {patient.data.name} с идентификатором {idPatientMis} уже существует",
            )
        kwargs["name"] = (
            f"{kwargs.get('familyName', '')} {kwargs.get('givenName', ' ')[:1]}. {kwargs.get('middleName', ' ')[:1]}."
        )
        kwargs["fullName"] = (
            f"{kwargs.get('familyName', '')} {kwargs.get('givenName', '')} {kwargs.get('middleName', '')}"
        )
        kwargs["birthDate"] = datetime.fromisoformat(kwargs.pop("birthDate"))
        utils.logger.info(
            f"Добавление пациента {kwargs.get('name', '')} с идентификатором {idPatientMis}"
        )
        patient = Patient(**kwargs)
        data = await patient.save()
        return utils.answer(data=data)

    @staticmethod
    async def getPatients(toDict: bool = True):
        patients = await CRUD.read(select(Patient), all=True)
        data = [patient.toDict() for patient in patients] if toDict else patients
        return utils.answer(data=data)

    @staticmethod
    async def getPatientByIdPatientMis(
        idPatientMis: str, toDict: bool = True, isCheck: bool = False
    ):

        if type(idPatientMis) != str:
            idPatientMis = str(idPatientMis)
        patient = await CRUD.read(
            select(Patient).where(Patient.idPatientMis == idPatientMis)
        )
        if patient:
            data = patient.toDict() if toDict else patient
            return utils.answer(data=data)

        if not isCheck:
            utils.logger.error(f"Пациент не найден, idPatientMis: {idPatientMis}")
        return utils.answer(success=False, message="Пациент не найден")

    @staticmethod
    async def editPatientrByIdPatientMis(idPatientMis: str, **kwargs):
        patient = await Patient.getPatientByIdPatientMis(idPatientMis, False)
        if not patient.success:
            utils.logger.error(f"Пациент не найден, idPatientMis: {idPatientMis}")
            return utils.answer(success=False, message="Пациент не найден")
        data = await patient.edit(**kwargs)
        return utils.answer(data=data)

    @staticmethod
    async def deletePatientrByIdPatientMis(idPatientMis: str) -> bool:
        try:
            patient = await Patient.getPatientByIdPatientMis(idPatientMis, False)
            await patient.data.delete()
            utils.logger.info(f"Пациент удален, idPatientMis: {idPatientMis}")
            return utils.answer()
        except:
            utils.logger.error(f"Пациент не удален, idPatientMis: {idPatientMis}")
            return utils.answer(success=False, message="Пациент не удален")
