import math
from datetime import datetime, timedelta

from pydantic import BaseModel

from mower.data import base_room_list
from mower.solvers.infra.drone import DroneSolver
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.solvers.infra.get_agent_from_room import GetAgentFromRoomSolver
from mower.solvers.infra.get_order_remaining_time import GetOrderRemainingTimeSolver
from mower.solvers.infra.reload import ReloadSolver
from mower.solvers.infra.run_order import RunOrderSolver
from mower.solvers.infra.run_order.read_original_order_remaining_time import (
    ReadOriginalOrderRemainTimeSolver,
)
from mower.solvers.infra.todo_list import TodoListSolver
from mower.utils import config
from mower.utils.config.plan import Facility
from mower.utils.digit_reader import get_drone
from mower.utils.log import logger
from mower.utils.scheduler import scheduler


class RunOrderRoomInfo(BaseModel):
    time: datetime | None = None
    "订单生成时间"
    room: str
    "房间名"
    plan: list[str]
    "但书/龙舌兰/佩佩的位置"
    dynamic: list[str] = []
    "跑单时的干员安排"


class RunOrderInfo:
    def __init__(self):
        """根据排班表获取跑单信息"""
        self.data: list[RunOrderRoomInfo] = []

        # 读排班表，找到替换组包含跑单干员的房间，生成跑单计划
        run_order_op = ["但书", "龙舌兰", "佩佩"]
        for room in base_room_list:
            if not room.startswith("room_"):
                continue
            facility: Facility = getattr(config.plan.plan1, room)
            run_order_room = False
            run_order_plan = []
            for plan in facility.plans:  # 站内位置
                op = ""
                for rep in plan.replacement:  # 一个位置的替换
                    if rep in run_order_op:
                        run_order_room = True
                        op = rep
                        break
                run_order_plan.append(op)
                if run_order_room:
                    self.data.append(RunOrderRoomInfo(room=room, plan=run_order_plan))
        logger.info(f"跑单房间：{[i.room for i in self.data]}")

    def update(self):
        """读订单剩余时间和房间内的干员"""
        for i, info in enumerate(self.data):
            if info.time is not None:
                continue
            logger.info(f"读取房间{info.room}的信息")

            info.time = (
                timedelta(seconds=GetOrderRemainingTimeSolver().run(info.room))
                + datetime.now()
            )
            info.dynamic = info.plan.copy()
            if "" in info.plan:
                current = GetAgentFromRoomSolver().run(info.room)
                for i, op in enumerate(current):
                    if info.plan[i] == "":
                        info.dynamic[i] = op["agent"]
        self.data.sort(key=lambda x: x.time)

        for r in self.data:
            logger.info(f"房间{r.room}的跑单时间为{r.time}，干员安排{r.dynamic}")


class MiniBase:
    """
    只保存干员心情数据，根据历史与当前心情数据无状态地生成任务
    1. 收产物
    2. 跑单
        - 没有订单就继续
        - 有一笔订单在前置时间以内就跑这一单
        - 有多笔订单在前置时间以内，按时间用无人机跑前面几单
    3. 读取干员信息
    4. 换班
        - 修正与排班表不一致的地方
        - 休息好的干员换上来
        - 心情低的干员安排休息
        - 肥鸭充能
    5. 无人机加速、搓玉补货
    6. 生成任务
        - 跑单
        - 肥鸭充能
        - 心情恢复结束
        - 暖机干员下班
    """

    solver_name = "基建·青春版"

    def run(self):
        self.run_order = RunOrderInfo()

        pre_delay = timedelta(minutes=config.conf.run_order_delay)

        # 1. 收产物
        TodoListSolver().run()

        # 2. 跑单
        self.run_order.update()

        # 立即跑单
        for info in self.run_order.data:
            threshold = datetime.now() + pre_delay
            if info.time < threshold:
                RunOrderSolver().run(room=info.room, agent_list=info.dynamic)
                info.time = None
            else:
                break

        # 3. 读取干员信息，先不管以前的数据
        # op_data = {}
        # for room in base_room_list:
        #     op_data[room] = GetAgentFromRoomSolver().run(room)

        # 4. 换班

        # 5. 无人机加速（仅支持制造站）
        DroneSolver().run(config.conf.drone_room)
        # 搓玉补货
        if config.conf.reload_room != "":
            for room in config.conf.reload_room.split(","):
                ReloadSolver().run(room)

        # 6. 生成任务
        # 重新读订单时间
        self.run_order.update()
        # 拉开时间接近的订单
        # 倒序遍历，依次加速较早的订单
        rev_iter = reversed(self.run_order.data)
        task_b = next(rev_iter)
        for task_a in rev_iter:
            # delta为至少需要加速的时间
            delta = task_a.time + pre_delay - task_b.time
            if delta <= timedelta():
                continue
            # 如果现在距加速之后不足跑单前置时间，所有更早的站无人机跑单
            if task_b.time - pre_delay < datetime.now():
                for info in self.run_order.data:
                    if info == task_b:
                        break
                    RunOrderSolver().run(
                        room=info.room, agent_list=info.dynamic, drone=True
                    )
                    info.time = None
                self.run_order.update()
                break
            # 无人机拉开间隔
            EnterRoomSolver().run(task_a.room, detail=False)
            total = get_drone(config.recog.gray)
            time_no_efficiency = timedelta(
                seconds=ReadOriginalOrderRemainTimeSolver().run(task_a.room)
            )
            time_with_efficiency = task_a.time - datetime.now()
            efficiency = round(time_no_efficiency / time_with_efficiency, 2)
            time_per_drone = timedelta(minutes=3) / efficiency
            drone = math.ceil(delta / time_per_drone)
            DroneSolver().run(task_a.room, drone, cur_count=total)
            task_a.time = (
                timedelta(seconds=GetOrderRemainingTimeSolver().run(task_a.room))
                + datetime.now()
            )
            task_b = task_a

        scheduler.register_one_time(
            solver="mower.solvers.mini_base.MiniBase",
            time=self.run_order.data[0].time - pre_delay,
        )
        return True
