import datetime

import cv2
from sqlalchemy import Column, Date, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

from mower.models import Digtal
from mower.utils import config
from mower.utils.digit_reader import DigitReader
from mower.utils.email import report_template, send_message
from mower.utils.graph import SceneGraphSolver
from mower.utils.image import cropimg, thres2
from mower.utils.log import logger
from mower.utils.path import get_path
from mower.utils.recognize import Scene, tp

Base = declarative_base()


# Database model for reports
class Report(Base):
    __tablename__ = "reports"

    id = Column(Integer, primary_key=True, autoincrement=True)
    date = Column(Date, nullable=False, unique=True)
    作战录像 = Column(Integer)
    赤金 = Column(Integer)
    龙门币订单 = Column(Integer)
    龙门币订单数 = Column(Integer)
    合成玉 = Column(Integer)
    合成玉订单数量 = Column(Integer)


class ReportSolver(SceneGraphSolver):
    def __init__(self) -> None:
        super().__init__()
        self.db_path = get_path("@app/tmp/report.db")
        self.low_range_gray = (100, 100, 100)
        self.high_range_gray = (255, 255, 255)
        self.date = (datetime.datetime.now() - datetime.timedelta(hours=4)).date()
        self.digitReader = DigitReader()
        self.report_res = {
            "作战录像": None,
            "赤金": None,
            "龙门币订单": None,
            "龙门币订单数": None,
            "合成玉": None,
            "合成玉订单数量": None,
        }
        self.reload_time = 0

        # Setup SQLAlchemy with dynamic DATABASE_URL
        self.DATABASE_URL = f"sqlite:///{self.db_path}"  # Dynamic DB URL
        self.engine = create_engine(self.DATABASE_URL)
        Base.metadata.create_all(self.engine)
        self.Session = sessionmaker(bind=self.engine)

    def run(self):
        if self.has_record():
            logger.info("今天的基报看过了")
            return True
        logger.info("康康大基报捏~")
        try:
            super().run()
            return True
        except Exception as e:
            logger.exception(e)
        return False

    def transition(self) -> bool:
        if self.scene() == Scene.RIIC_REPORT:
            return self.read_report()
        else:
            self.scene_graph_step(Scene.RIIC_REPORT)

    def read_report(self):
        if self.find("riic/manufacture"):
            try:
                self.crop_report()
                logger.info(self.report_res)
                self.record_report()
            except Exception as e:
                logger.exception("基报读取失败:{}".format(e))
            return True
        else:
            if self.reload_time > 3:
                logger.info("未加载出基报")
                return True
            self.reload_time += 1
            self.sleep(1)

    def record_report(self):
        logger.info(f"存入{self.date}的数据{self.report_res}")
        try:
            with self.Session() as session:
                report = Report(
                    date=self.date,
                    作战录像=self.report_res["作战录像"],
                    赤金=self.report_res["赤金"],
                    龙门币订单=self.report_res["龙门币订单"],
                    龙门币订单数=self.report_res["龙门币订单数"],
                    合成玉=self.report_res["合成玉"],
                    合成玉订单数量=self.report_res["合成玉订单数量"],
                )
                session.merge(report)
                session.commit()

        except Exception as e:
            logger.exception(f"存入数据失败：{e}")
        self.tap((1253, 81), interval=2)
        try:
            send_message(
                report_template.render(
                    report_data=self.report_res, title_text="基建报告"
                ),
                "基建报告",
                "INFO",
                attach_image=config.recog.img,
            )
        except Exception as e:
            logger.exception(f"基报邮件发送失败：{e}")
        self.tap((40, 80), interval=2)

    def has_record(self):
        try:
            with self.Session() as session:  # 使用上下文管理器
                record_exists = session.query(Report).filter_by(date=self.date).first()
                return record_exists is not None
        except Exception as e:
            logger.exception(f"查询数据库失败：{e}")
            return False

    def crop_report(self):
        exp_area = [[1625, 200], [1800, 230]]
        iron_pos = self.find("riic/iron")
        iron_area = [
            [iron_pos[1][0], iron_pos[0][1]],
            [1800, iron_pos[1][1]],
        ]
        trade_pt = self.find("riic/trade")
        assist_pt = self.find("riic/assistants")
        area = {
            "iron_order": [[1620, trade_pt[1][1] + 10], [1740, assist_pt[0][1] - 50]],
            "iron_order_number": [
                [1820, trade_pt[1][1] + 10],
                [1870, assist_pt[0][1] - 65],
            ],
            "orundum": [[1620, trade_pt[1][1] + 45], [1870, assist_pt[0][1]]],
            "orundum_number": [
                [1820, trade_pt[1][1] + 55],
                [1860, assist_pt[0][1] - 20],
            ],
        }

        img = cv2.cvtColor(config.recog.img, cv2.COLOR_RGB2HSV)
        img = cv2.inRange(img, (98, 0, 150), (102, 255, 255))
        self.report_res["作战录像"] = self.get_number(img, exp_area, height=19)
        self.report_res["赤金"] = self.get_number(img, iron_area, height=19)
        self.report_res["龙门币订单"] = self.get_number(
            img, area["iron_order"], height=19
        )
        self.report_res["合成玉"] = self.get_number(img, area["orundum"], height=19)
        logger.info("蓝字读取完成")

        img = cv2.cvtColor(config.recog.img, cv2.COLOR_RGB2HSV)
        img = cv2.inRange(img, (0, 0, 50), (100, 100, 170))
        self.report_res["龙门币订单数"] = self.get_number(
            img, area["iron_order_number"], height=19, thres=200
        )
        self.report_res["合成玉订单数量"] = self.get_number(
            img, area["orundum_number"], height=19, thres=200
        )
        logger.info("订单数读取完成")

    def get_number(
        self, img, scope: tp.Scope, height: int | None = 18, thres: int | None = 100
    ):
        img = cropimg(img, scope)

        default_height = 29
        if height and height != default_height:
            scale = default_height / height
            img = cv2.resize(img, None, None, scale, scale)
        img = thres2(img, thres)
        contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        rect = [cv2.boundingRect(c) for c in contours]
        rect.sort(key=lambda c: c[0])
        value = 0
        for x, y, w, h in rect:
            digit = cropimg(img, ((x, y), (x + w, y + h)))
            digit = cv2.copyMakeBorder(
                digit, 10, 10, 10, 10, cv2.BORDER_CONSTANT, None, (0,)
            )

            score = []
            for i in range(10):
                im = Digtal().noto_sans[i]
                result = cv2.matchTemplate(digit, im, cv2.TM_SQDIFF_NORMED)
                min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
                score.append(min_val)
            value = value * 10 + score.index(min(score))

        return value

    def get_report_data(self):
        # 连接数据库
        try:
            with self.Session() as session:
                format_data = []

                # 查询所有报告数据
                records = session.query(Report).all()

                # 将记录转化为所需格式
                for record in records:
                    format_data.append(
                        {
                            "日期": record.date.strftime(
                                "%Y-%m-%d"
                            ),  # 日期格式化为字符串
                            "作战录像": record.作战录像,
                            "赤金": record.赤金,
                            "制造总数": int(record.赤金 + record.作战录像),
                            "龙门币订单": record.龙门币订单,
                            "反向作战录像": -record.作战录像,
                            "龙门币订单数": record.龙门币订单数,
                            "每单获取龙门币": int(
                                record.龙门币订单 / record.龙门币订单数
                            )
                            if record.龙门币订单数
                            else 0,
                        }
                    )

                # 如果格式化后的数据少于15条，则添加缺失的日期
                earliest_date = (
                    min(record.date for record in records)
                    if records
                    else datetime.date.today()
                )
                if len(format_data) < 15:
                    for i in range(1, 16 - len(format_data)):
                        format_data.insert(
                            0,
                            {
                                "日期": (
                                    earliest_date - datetime.timedelta(days=i + 1)
                                ).strftime("%Y-%m-%d"),
                                "作战录像": "-",
                                "赤金": "-",
                                "龙门币订单": "-",
                                "龙门币订单数": "-",
                                "每单获取龙门币": "-",
                            },
                        )

                logger.debug(format_data)
                return format_data

        except Exception as e:
            logger.exception(f"读取数据库失败: {e}")

    def get_orundum_data(self):
        try:
            format_data = []
            with self.Session() as session:
                # 查询所有报告数据
                records = session.query(Report).all()
                earliest_date = datetime.datetime.now()

                # 初始化制造合成玉的开始日期
                begin_make_orundum = (earliest_date + datetime.timedelta(days=1)).date()

                if len(records) >= 15:
                    for i in range(len(records) - 1, -1, -1):
                        record = records[i]
                        if 0 < i < len(records) - 15:
                            continue
                        if record.合成玉 > 0:
                            begin_make_orundum = record.date

                else:
                    for record in records:
                        if record.合成玉 > 0:
                            begin_make_orundum = record.date

                if begin_make_orundum > earliest_date.date():
                    return format_data

                total_orundum = 0
                for record in records:
                    total_orundum += record.合成玉
                    format_data.append(
                        {
                            "日期": record.date.strftime("%Y-%m-%d"),
                            "合成玉": record.合成玉,
                            "合成玉订单数量": record.合成玉订单数量,
                            "抽数": round((record.合成玉 / 600), 1),
                            "累计制造合成玉": total_orundum,
                        }
                    )

                if len(format_data) < 15:
                    earliest_date = records[0].date
                    for i in range(1, 16 - len(format_data)):
                        format_data.insert(
                            0,
                            {
                                "日期": (
                                    earliest_date - datetime.timedelta(days=i + 1)
                                ).strftime("%Y-%m-%d"),
                                "合成玉": "-",
                                "合成玉订单数量": "-",
                                "抽数": "-",
                                "累计制造合成玉": 0,
                            },
                        )

            logger.debug(format_data)
            return format_data

        except Exception as e:
            logger.exception(f"获取合成玉数据失败：{e}")
            return []

    def close_engine(self):
        self.engine.dispose()

    def __del__(self):
        self.close_engine()
