from datetime import datetime
from sqlalchemy import Column, DateTime, ForeignKey, Integer, select

from db import CRUD, Base
from db.schemas.signings import Signing
from utils import answer, logger, toDict


class Statuses(Base):
    __tablename__ = "statuses"

    id = Column(Integer, primary_key=True, index=True)
    singingId = Column(Integer, ForeignKey("signings.id", ondelete="CASCADE"))
    status = Column(Integer)
    created_at = Column(DateTime, default=datetime.now)

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

    def toDict(self):
        return toDict(self)

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

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

    @staticmethod
    async def addStatus(singingId: int, status: int):
        if type(singingId) != int:
            singingId = int(singingId)
        if type(status) != int:
            status = int(status)
        await CRUD.create(Statuses(singingId=singingId, status=status))

    @staticmethod
    async def getStatus(singingId: int) -> list:
        if type(singingId) != int:
            singingId = int(singingId)
        return await CRUD.read(
            select(Statuses)
            .where(Statuses.singingId == singingId)
            .order_by(Statuses.created_at),
            True,
        )

    @staticmethod
    async def updateStatus(singingId: int, isNew: bool = False):
        from api.n3health import getTrackingIDSigning

        if type(singingId) != int:
            singingId = int(singingId)

        singingData = await Signing.getSigningById(singingId, False)
        if not singingData.success:
            logger.error(singingData.message)
            return singingData

        statusDB = await Statuses.getStatus(singingId)
        latestStatusCode = 0
        try:
            latestStatusCode = statusDB[-1].status
        except IndexError:
            pass

        statusData = await getTrackingIDSigning(
            singingData.data.trackingId, latestStatusCode, singingId
        )
        if not statusData.success:
            logger.error(statusData.message)
            return statusData

        actualStatusCode = int(statusData.data["code"])
        if actualStatusCode == 0 and isNew:
            actualStatusCode = 201

        if latestStatusCode != actualStatusCode:
            logger.info(f"✔️ Обновился статус: {singingId} - {actualStatusCode}")
            await Statuses.addStatus(singingId, actualStatusCode)
        else:
            logger.info(f"📌 Статус не изменился: {singingId} - {actualStatusCode}")

        if actualStatusCode == 204:
            logger.info(f"✅ Подписание завершено: {singingId}")
            await singingData.data.edit(storagePath=statusData.data["storagePath"])

        if actualStatusCode > 204:
            logger.info(f"❌ Подписание не успешно: {statusData.data['description']}")
            await singingData.data.edit(trackingId=None)

        return answer()
