from datetime import datetime, timedelta

from sqlalchemy import select

from db.handlers.stock import StockHandler
from db.schemas.records import StocksRecords, ServicesRecords
from utils import logger


class StocksRecordsHandler:

    async def add(
        action: str,
        source_stock_id: int,
        target_stock_id: int,
        toolkit_id: int,
        init_user_id: int,
        reason: str,
        quantity: int,
        price: float,
        source_toolbox_id: int = None,
        target_toolbox_id: int = None,
        return_record: bool = False,
    ):
        recordData = {
            "action": action,
            "source_stock_id": source_stock_id,
            "target_stock_id": target_stock_id,
            "source_toolbox_id": source_toolbox_id,
            "target_toolbox_id": target_toolbox_id,
            "toolkit_id": toolkit_id,
            "init_user_id": init_user_id,
            "reason": reason,
            "quantity": quantity,
            "price": price,
        }
        try:
            logger.debug(f"Создание записи: {action} от {init_user_id}")
            logger.debug(recordData)
            record = StocksRecords(**recordData)
            await record.save()
            logger.debug(f"Запись успешно создана, id: {record.id}")
            return True if not return_record else record
        except Exception as e:
            logger.error(f"Ошибка создания записи: {str(e)}")
            return False

    async def decide(
        record: StocksRecords,
        decision_user_id: int,
        source_stock_id: int,
        quantity: int,
        price: float,
        accept: bool = True,
    ):
        try:
            logger.debug(
                f"{'Принятие' if accept else 'Отклонение'} записи {record.id} от {decision_user_id}"
            )
            record.decision_user_id = decision_user_id
            record.decided_at = datetime.now()
            record.source_stock_id = source_stock_id
            record.quantity = quantity
            record.price = price
            record.accepted = accept
            await record.save()
            logger.debug(
                f"Запись {record.id} успешно {'принята' if accept else 'отклонена'} {decision_user_id} в {record.decided_at.strftime('%Y-%m-%d %H:%M:%S')}"
            )
            return True
        except Exception as e:
            logger.error(
                f"Ошибка {'принятия' if accept else 'отклонения'} записи: {str(e)}"
            )
            return False

    async def edit(record_id: int, edit_user_id: int, **kwargs):
        def updateStockRecord(recordDB, editData):
            whatchList = ["toolkit_id", "quantity", "price", "placement"]
            for key in whatchList:
                if key in editData:
                    setattr(recordDB, key, editData[key])
            return recordDB

        try:
            logger.debug(f"Обновление записи {record_id} от {edit_user_id}")

            record = await StocksRecords.get(id=record_id)
            record.edit_user_id = edit_user_id
            record.edited_at = datetime.now()

            logger.debug("Вносим изменения в записи о движении инструмента")

            if record.source_stock_id:
                logger.debug(
                    "Вносим изменения в записи о движении инструмента из исходного склада"
                )
                sourceStockRecord = await StockHandler.get(
                    record.source_stock_id, record=True
                )
                if "source_toolbox_id" in kwargs:
                    sourceStockRecord.toolbox_id = kwargs["source_toolbox_id"]

                sourceStockRecord = updateStockRecord(sourceStockRecord, kwargs)
                await sourceStockRecord.save()
                logger.debug(
                    "Внесли изменения в записи о движении инструмента из исходного склада"
                )

            if record.target_stock_id:
                logger.debug(
                    "Вносим изменения в записи о движении инструмента в целевой склад"
                )
                targetStockRecord = await StockHandler.get(
                    record.target_stock_id, record=True
                )
                if "target_toolbox_id" in kwargs:
                    targetStockRecord.toolbox_id = kwargs["target_toolbox_id"]

                targetStockRecord = updateStockRecord(targetStockRecord, kwargs)
                await targetStockRecord.save()
                logger.debug(
                    "Внесли изменения в записи о движении инструмента в целевой склад"
                )

            logger.debug("Внесли изменения в записи о движении инструмента")

            edited = {}
            for key, value in kwargs.items():
                originalValue = getattr(record, key)
                setattr(record, key, value)
                edited[key] = {"original": originalValue, "new": value}
            record.edited = edited
            await record.save()
            logger.debug(
                f"Запись {record_id} успешно обновлена {edit_user_id} в {record.updated_at.strftime('%Y-%m-%d %H:%M:%S')}"
            )
            logger.debug(edited)
            return True

        except Exception as e:
            logger.error(f"Ошибка обновления записи: {str(e)}")
            return False

    async def get(user_id: int = None, days: int = 30):
        from db import CRUD

        try:
            if user_id:
                userInfo = f"пользователя {user_id} "
                decided = "не решенных "
                daysLimit = ""
                query = select(StocksRecords).where(
                    StocksRecords.init_user_id == user_id,
                    StocksRecords.decision_user_id == None,
                )
            else:
                userInfo = "всех пользователей "
                decided = ""
                daysLimit = f"за последние {days} дн."
                query = select(StocksRecords).where(
                    StocksRecords.created_at > datetime.now() - timedelta(days=days),
                )
            logger.debug(f"Получение всех {decided}записей {userInfo}{daysLimit}")
            records = await CRUD.read(query, True)
            logger.debug(
                f"{len(records)} {decided}записей {userInfo}{daysLimit} успешно получены"
            )
            if len(records) == 0:
                return []
            records.sort(key=lambda x: x.created_at, reverse=True)
            recordsData = [record.toDict() for record in records]
            logger.debug(recordsData)
            return recordsData
        except Exception as e:
            logger.error(f"Ошибка получения записей: {str(e)}")
            return False

    async def getById(record_id: int, record: bool = False):
        from db import CRUD

        try:
            logger.debug(f"Получение записи {record_id}")
            query = select(StocksRecords).where(StocksRecords.id == record_id)
            stocksRecord = await CRUD.read(query)
            if not stocksRecord:
                logger.debug(f"Запись {record_id} не найдена")
                return False
            logger.debug(f"Запись {record_id} успешно получена")
            return stocksRecord.toDict() if not record else stocksRecord
        except Exception as e:
            logger.error(f"Ошибка получения записи: {str(e)}")
            return False

    async def getOriginalToolboxId(toolkitId: int, targetToolboxId: int):
        from db import CRUD

        try:
            logger.debug(
                f"Получение записи о перемещении инструмента {toolkitId} на склад {targetToolboxId}"
            )
            query = select(StocksRecords).where(
                StocksRecords.toolkit_id == toolkitId,
                StocksRecords.target_toolbox_id == targetToolboxId,
            )
            stocksRecord = await CRUD.read(query)
            if not stocksRecord:
                logger.debug(f"Запись {toolkitId} не найдена")
                return False
            logger.debug(f"Запись {toolkitId} успешно получена")
            return stocksRecord.source_toolbox_id
        except Exception as e:
            logger.error(f"Ошибка получения записи: {str(e)}")
            return False


class ServiceRecordsHandler:
    async def add(user_id: int, details: dict):
        try:
            logger.debug(f"Создание записи: {user_id}")
            logger.debug(details)
            record = ServicesRecords(user_id=user_id, details=details)
            await record.save()
            logger.debug(f"Запись успешно создана, id: {record.id}")
            return True
        except Exception as e:
            logger.error(f"Ошибка создания записи: {str(e)}")
            return False

    async def get(user_id: int = None, days: int = 30):
        from db import CRUD

        try:
            if user_id:
                userInfo = f"пользователя {user_id} "
                daysLimit = ""
                query = select(ServicesRecords).where(
                    ServicesRecords.user_id == user_id,
                )
            else:
                userInfo = "всех пользователей "
                daysLimit = f"за последние {days} дн."
                query = select(ServicesRecords).where(
                    ServicesRecords.created_at > datetime.now() - timedelta(days=days),
                )
            logger.debug(f"Получение всех записей {userInfo}{daysLimit}")
            records = await CRUD.read(query, True)
            logger.debug(
                f"{len(records)} записей {userInfo}{daysLimit} успешно получены"
            )
            if len(records) == 0:
                return []
            records.sort(key=lambda x: x.created_at, reverse=True)
            recordsData = [record.toDict() for record in records]
            logger.debug(recordsData)
            return recordsData
        except Exception as e:
            logger.error(f"Ошибка получения записей: {str(e)}")
            return False
