from typing import Literal, get_args, get_origin

from pydantic import BaseModel, model_validator
from pydantic_core import PydanticUndefined


class ConfModel(BaseModel):
    @model_validator(mode="before")
    @classmethod
    def nested_defaults(cls, data):
        for name, field in cls.model_fields.items():
            if name not in data:
                if field.default is PydanticUndefined:
                    data[name] = field.annotation()
                else:
                    data[name] = field.default
            else:
                value = data[name]
                expected_type = field.annotation

                # 处理嵌套的 BaseModel
                if isinstance(field.annotation, type) and issubclass(
                    field.annotation, BaseModel
                ):
                    if not isinstance(value, dict):  # 确保嵌套类型为字典
                        value = {}
                    # 递归调用嵌套模型的验证器
                    data[name] = field.annotation(**value)

                # 检查 Literal 类型并修正
                elif get_origin(expected_type) is Literal:
                    valid_literals = get_args(expected_type)
                    if value not in valid_literals:
                        # 修正为默认值
                        data[name] = (
                            field.default
                            if field.default is not PydanticUndefined
                            else None
                        )

        return data


class CluePart(ConfModel):
    class CreditFightConf(ConfModel):
        direction: str = "Right"
        "部署方向"
        operator: str = "风笛"
        "使用干员"
        skill: int = 1
        "技能"
        squad: int = 1
        "编队序号"
        x: int = 5
        "横坐标"
        y: int = 3
        "纵坐标"

    maa_credit_fight: bool = True
    "信用作战开关"
    credit_fight: CreditFightConf
    "信用作战设置"
    enable_party: int = 1
    "线索收集"
    leifeng_mode: int = 1
    "雷锋模式"
    maa_mall_blacklist: str = "加急许可,碳,碳素,家具零件"
    "黑名单"
    maa_mall_buy: str = "招聘许可,技巧概要·卷2"
    "优先购买"
    maa_mall_ignore_blacklist_when_full: bool = False
    "信用溢出时无视黑名单"


class EmailPart(ConfModel):
    class CustomSMTPServerConf(ConfModel):
        enable: bool = False
        "启用自定义邮箱"
        server: str = ""
        "SMTP服务器"
        encryption: str = "starttls"
        "加密方式"
        ssl_port: int = 587
        "端口号"

    mail_enable: int = 0
    "邮件提醒"
    account: str = ""
    "邮箱用户名"
    pass_code: str = ""
    "邮箱密码"
    recipient: list[str] = []
    "收件人"
    custom_smtp_server: CustomSMTPServerConf
    "自定义邮箱"
    mail_subject: str = "[mower-ng通知]"
    "标题前缀"
    notification_level: str = "INFO"
    "邮件通知等级"


class ExtraPart(ConfModel):
    class WebViewConf(ConfModel):
        port: int = 58000
        "端口号"
        width: int = 1450
        "窗口宽度"
        height: int = 850
        "窗口高度"
        token: str = ""
        "远程连接密钥"
        scale: float = 1
        "网页缩放"
        tray: bool = True
        "托盘图标"

    class WaitingSceneConf(ConfModel):
        CONNECTING: tuple[int, int] = (1000, 15)
        UNKNOWN: tuple[int, int] = (0, 10)
        UNKNOWN_WITH_NAVBAR: tuple[int, int] = (0, 5)
        LOADING: tuple[int, int] = (3000, 60)
        LOGIN_LOADING: tuple[int, int] = (3000, 30)
        LOGIN_MAIN_NOENTRY: tuple[int, int] = (3000, 30)
        OPERATOR_ONGOING: tuple[int, int] = (10000, 300)

    start_automatically: bool = False
    "启动后自动开始任务"
    webview: WebViewConf
    "GUI相关设置"
    theme: Literal["light", "dark"] = "light"
    "界面主题"
    screenshot_interval: int = 500
    "截图最短间隔（毫秒）"
    screenshot: float = 24
    "截图保留时长（小时）"
    waiting_scene_v2: WaitingSceneConf
    "等待时间"


class FightPart(ConfModel):
    class ChooseConf(ConfModel):
        add_low_trust_opers: bool = False
        "补充低信赖干员"

    class SupportConf(ConfModel):
        elite: int = 2
        "精英化"
        level: int = 60
        "等级"
        refresh: int = 10
        "最大刷新次数"

    class WorkConf(ConfModel):
        class WorkItem(ConfModel):
            stage: str = ""
            "关卡"
            retry_times: int = 2
            "重试次数"

        squad: int = 0
        "作战编队"
        use_medicine: bool = True
        "是否使用理智药"
        enemy_breach_strategy: Literal["overlook", "give_up", "restart_game"] = (
            "give_up"
        )
        "被敌人进入时采取的策略"
        intelligent_select: bool = True
        "智能选择"
        works: list[WorkItem] = []
        "自动作战列表"

    work_enable: bool = False
    "是否执行自动作战列表"
    avatar_recog_pause: bool = False
    "作战中识别干员时暂停"
    first_swipe_duration: int = 400
    "部署干员第一段滑动持续时间"
    second_swipe_duration: int = 200
    "部署干员第二段滑动(滑方向)持续时间"
    choose: ChooseConf
    "自动选干员设置"
    support: SupportConf
    "借助战要求"
    work: WorkConf
    "自动作战列表设置"


class LongTaskPart(ConfModel):
    class RogueConf(ConfModel):
        squad: str = ""
        "分队"
        roles: str = ""
        "职业"
        core_char: str = ""
        "干员"
        use_support: bool = False
        "开局干员使用助战"
        use_nonfriend_support: bool = False
        "开局干员使用非好友助战"
        mode: int = 1
        "策略"
        refresh_trader_with_dice: bool = False
        "刷新商店（指路鳞）"
        expected_collapsal_paradigms: list[str] = [
            "目空一些",
            "睁眼瞎",
            "图像损坏",
            "一抹黑",
        ]
        "需要刷的坍缩范式"

    class ReclamationAlgorithmConf(ConfModel):
        timeout: int = 30
        "生息演算和隐秘战线的超时时间"

    class SecretFrontConf(ConfModel):
        target: str = "结局A"
        "隐秘战线结局"

    class SSSConf(ConfModel):
        choose_agent: bool = True
        "自动编队"
        mode: Literal["normal", "ex"] = "normal"
        "难度：正常为normal，应急为ex"
        finish_while_full: bool = True
        "模组刷满时直接结束"
        ope_limit_stage: int = 6
        "使用代理卡最低层数要求"

    maa_rg_enable: int = 0
    "大型任务"
    maa_long_task_type: str = "rogue"
    "大型任务类型"
    maa_rg_sleep_max: str = "0:00"
    "开始时间"
    maa_rg_sleep_min: str = "0:00"
    "停止时间"
    maa_rg_theme: Literal["Phantom", "Mizuki", "Sami", "Sarkaz"] = "Sarkaz"
    "肉鸽主题"
    rogue: RogueConf
    "肉鸽设置"
    reclamation_algorithm: ReclamationAlgorithmConf
    "生息演算"
    secret_front: SecretFrontConf
    "隐秘战线"
    sss: SSSConf
    "保全派驻"


class MaaPart(ConfModel):
    maa_path: str = "D:\\MAA-v4.13.0-win-x64"
    maa_conn_preset: str = "General"
    maa_touch_option: str = "maatouch"


class RecruitPart(ConfModel):
    recruit_enable: bool = True
    "公招开关"
    recruit_robot: bool = True
    "保留支援机械标签"
    recruitment_permit: int = 30
    "三星招募阈值"
    recruit_gap: float = 9
    "启动间隔"
    recruit_auto_5: int = 1
    "五星招募策略，1自动，2手动"
    recruit_auto_only5: bool = False
    "五星词条组合唯一时自动选择"


class RegularTaskPart(ConfModel):
    class WeeklyConf(BaseModel):
        general: list[str]
        "常驻关卡"
        custom: list[str]
        "自定义关卡"

    class SignInConf(ConfModel):
        enable: bool = True
        "签到活动开关"

    check_mail_enable: bool = True
    "领取邮件奖励"
    delete_read_mail: bool = False
    "删除已读邮件"
    maa_enable: bool = True
    "日常任务"
    maa_gap: float = 3
    "日常任务间隔"
    use_all_medicine: bool = False
    "自动使用全部理智药"
    maa_expiring_medicine: bool = True
    "自动使用将要过期（约3天）的理智药"
    exipring_medicine_on_weekend: bool = False
    "仅在周末使用将要过期的理智药"
    weekly_plan: list[WeeklyConf] = [{"general": [], "custom": []}] * 7
    "刷理智周计划，周一开始"
    custom_stages: list[str | None] = [None] * 3
    "刷理智自定义关卡"
    maa_depot_enable: bool = False
    "仓库物品混合读取"
    visit_friend: bool = True
    "访问好友"
    report_enable: bool = True
    "读取基报"
    switch_assistants: bool = True
    "切换高信赖基建副手"
    sign_in: SignInConf
    "签到活动"
    trade_token: bool = False
    "兑换溢出信物"


class RIICPart(ConfModel):
    class RunOrderGrandetModeConf(ConfModel):
        enable: bool = True
        "葛朗台跑单开关"
        buffer_time: int = 15
        "缓冲时间"
        back_to_index: bool = False
        "跑单前返回基建首页"

    drone_count_limit: int = 100
    "无人机使用阈值"
    drone_room: str = ""
    "无人机使用房间"
    drone_interval: float = 3
    "无人机加速间隔"
    free_blacklist: str = ""
    "宿舍黑名单"
    reload_room: str = ""
    "搓玉补货房间"
    run_order_delay: float = 3
    "跑单前置延时"
    resting_threshold: float = 0.65
    "心情阈值"
    run_order_grandet_mode: RunOrderGrandetModeConf
    "葛朗台跑单"
    free_room: bool = False
    "宿舍不养闲人模式"
    trust_limit: int = 200
    "信赖值阈值"


class EmulatorPart(ConfModel):
    class EmulatorConf(ConfModel):
        name: str = "MuMu12"
        "名称"
        index: str | int = "0"
        "多开编号"
        emulator_folder: str = ""
        "文件夹"
        wait_time: int = 30
        "启动时间"
        hotkey: str = ""
        "老板键"

    class CustomScreenshotConf(ConfModel):
        command: str = "adb -s 127.0.0.1:5555 shell screencap -p 2>/dev/null"
        "截图命令"

    class TapToLaunchGameConf(ConfModel):
        enable: bool = False
        "点击屏幕启动游戏"
        x: int = 0
        "横坐标"
        y: int = 0
        "纵坐标"

    class DroidCastConf(ConfModel):
        rotate: bool = False
        "将截图旋转180度"

    class DroidCastRawConf(ConfModel):
        orientation: Literal["portrait", "landscape"] = "landscape"
        "屏幕方向"
        rotate: Literal[0, 90, 180, 270] = 0
        "截图旋转角度"

    class MuMuMultiAppConf(ConfModel):
        user_id: str = "0"
        "用户ID"
        app_index: int = 0
        "应用分身编号"

    adb: str = "127.0.0.1:16384"
    "ADB连接地址"
    server_port: int = 0
    "ADB服务器端口"
    emulator: EmulatorConf
    "模拟器"
    maa_adb_path: str = ""
    "ADB路径"
    package_type: int = 1
    "游戏服务器"
    droidcast: DroidCastConf
    "DroidCast截图设置"
    droidcast_raw: DroidCastRawConf
    "DroidCast截图设置"
    custom_screenshot: CustomScreenshotConf
    "自定义截图"
    tap_to_launch_game: TapToLaunchGameConf
    "点击屏幕启动游戏"
    mumu_multi_app: MuMuMultiAppConf
    "MuMu应用分身"
    strategy_when_idle: Literal[
        "do_nothing", "switch_to_home", "exit_game", "close_emulator"
    ] = "switch_to_home"
    "任务结束时采取的策略"
    kill_server_when_idle: bool = True
    "任务结束时关闭adb-server"
    screencap_strategy: Literal[
        "adb",
        "droidcast",
        "droidcast_raw",
        "mumuipc",
        "diy",
        "scrcpy",
    ] = "droidcast"
    "截图方案"
    control_strategy: Literal["scrcpy", "mumuipc"] = "scrcpy"
    "触控方案"
    app_control_strategy: Literal["adb", "mumumanager", "scrcpy", "adb_multiuser"] = (
        "adb"
    )
    "应用控制方案"


class SKLandPart(ConfModel):
    class SKLandAccount(BaseModel):
        account: str = ""
        "账号"
        password: str = ""
        "密码"
        cultivate_select: bool = True
        "服务器"
        isCheck: bool = True
        "签到"
        sign_in_bilibili: bool = False
        "官服签到"
        sign_in_official: bool = False
        "B服签到"

    skland_enable: bool = False
    "森空岛签到"
    skland_info: list[SKLandAccount] = []
    "森空岛账号"


class Conf(
    CluePart,
    EmailPart,
    ExtraPart,
    FightPart,
    LongTaskPart,
    MaaPart,
    RecruitPart,
    RegularTaskPart,
    RIICPart,
    EmulatorPart,
    SKLandPart,
):
    @property
    def APPNAME(self):
        return (
            "com.hypergryph.arknights"
            if self.package_type == 1
            else "com.hypergryph.arknights.bilibili"
        )

    @property
    def RG(self):
        return self.maa_rg_enable == 1 and self.maa_long_task_type == "rogue"

    @property
    def SSS(self):
        return self.maa_rg_enable == 1 and self.maa_long_task_type == "sss"

    @property
    def RA(self):
        return self.maa_rg_enable == 1 and self.maa_long_task_type == "ra"

    @property
    def SF(self):
        return self.maa_rg_enable == 1 and self.maa_long_task_type == "sf"

    @property
    def run_order_buffer_time(self):
        """
        >  0 葛朗台跑单的缓冲时间
        <= 0 无人机跑单
        """
        if self.run_order_grandet_mode.enable:
            return self.run_order_grandet_mode.buffer_time
        return -1
