#pragma once

#include <optional>

#include "Common/AsstBattleDef.h"
#include "MaaUtils/NoWarningCVMat.hpp"
#include "Task/AbstractTask.h"
#include "Ui/BattleQuickFormation.h"
#include "Ui/SupportList.h"
#include "Vision/TemplDetOCRer.h"

namespace asst
{

class BattleFormationTask : public AbstractTask
{
public:
    using AbstractTask::AbstractTask;
    BattleFormationTask(const AsstCallback& callback, Assistant* inst, std::string_view task_chain);
    virtual ~BattleFormationTask() override = default;

    enum class Filter
    {
        None,
        Trust,
        Cost,
    };

    struct AdditionalFormation
    {
        Filter filter = Filter::None;
        bool double_click_filter = true;
        battle::RoleCounts role_counts;
    };

    struct QuickFormationOper : public asst::TemplDetOCRer::Result
    {
        battle::Role role = battle::Role::Unknown;
        bool is_selected = false; // 是否选中
    };

    void append_additional_formation(AdditionalFormation formation) { m_additional.emplace_back(std::move(formation)); }

    // 设置追加自定干员列表
    void set_user_additional(std::vector<std::pair<std::string, int>> value) { m_user_additional = std::move(value); }

    // 是否追加低信赖干员
    void set_add_trust(bool add_trust) { m_add_trust = add_trust; }

    // 设置是否跳过未满足的干员属性要求
    void set_ignore_requirements(bool value) { m_ignore_requirements = value; }

    // 设置对指定编队自动编队
    void set_select_formation(int index) { m_select_formation_index = index; }

    std::shared_ptr<std::unordered_map<std::string, std::string>> get_opers_in_formation() const
    {
        return m_opers_in_formation;
    }

    enum class DataResource
    {
        Copilot,
        SSSCopilot,
    };

    void set_data_resource(DataResource resource) { m_data_resource = resource; }

    // ————————————————————————————————
    // 助战干员选择相关
    // ————————————————————————————————
    enum class SupportUnitUsage // 助战干员使用策略
    {
        None = 0,               // 不加助战干员
        WhenNeeded = 1,         // 如果仅缺一名干员则尝试补助战,
        Specific = 2,           // 如果仅缺一名干员则尝试补助战，如无缺失则使用指定助战干员
        Random = 3              // 如果仅缺一名干员则尝试补助战，如无缺失则随机加一个助战干员
    };

    void set_support_unit_usage(const SupportUnitUsage& value) { m_support_unit_usage = value; }

    // 是否在有且仅有一名缺失干员时尝试寻找助战干员补齐编队
    bool use_suppprt_unit_when_needed() const
    {
        return m_support_unit_usage == SupportUnitUsage::WhenNeeded ||
               m_support_unit_usage == SupportUnitUsage::Specific || m_support_unit_usage == SupportUnitUsage::Random;
    }

    bool set_specific_support_unit(const std::string& name = ""); // 设置指定助战干员

protected:
    using OperGroup = std::pair<std::string, std::vector<asst::battle::OperUsage>>;

    virtual bool _run() override;
    bool parse_formation();
    // 判断当前编队是否与上次相同, 同时为相同部分添加进已选中, return 是否完全相同
    bool compare_formation();
    bool is_formation_valid(const cv::Mat& img) const;
    bool select_formation(int select_index, const cv::Mat& img);
    bool enter_selection_page(const cv::Mat& img = cv::Mat());
    // 进入快捷编队清空选择后执行，快速选择非干员组的干员
    void formation_with_last_opers();
    bool add_formation(battle::Role role, const std::vector<OperGroup*>& oper_group);
    // 追加附加干员（按部署费用等小分类）
    bool add_additional();
    // 补充刷信赖的干员，从最小的开始
    bool add_trust_operators();
    // 选择当前页中的干员, return 是否继续翻页
    bool select_opers_in_cur_page(const std::vector<OperGroup*>& groups);
    // 检查干员等级
    bool check_oper_level(const cv::Mat& image, asst::Rect flag, const battle::OperUsage& oper, bool ignore);
    // 检查并选中技能, return 技能是否达到要求
    bool check_and_select_skill(const battle::OperUsage& oper, bool ignore, int delay);
    void swipe_page();
    void swipe_to_the_left(int times = 2);
    bool confirm_selection();
    bool click_role_table(battle::Role role);
    bool select_random_support_unit();
    void report_missing_operators();
    // 干员组中有干员已被选中
    bool has_oper_selected(const std::vector<asst::battle::OperUsage>& opers) const;
    bool has_oper_unchecked(const std::vector<asst::battle::OperUsage>& opers) const;

    std::vector<QuickFormationOper> analyzer_opers(const cv::Mat& image);

    std::unordered_map<battle::Role, std::vector<OperGroup>> m_formation;      // 作业编队
    std::unordered_map<battle::Role, std::vector<OperGroup>> m_formation_last; // 上次的编队
    // 编队中的干员名称-所属组名, 传递给外部使用, 编入的干员需要存入该表
    std::shared_ptr<std::unordered_map<std::string, std::string>> m_opers_in_formation =
        std::make_shared<std::unordered_map<std::string, std::string>>();
    bool m_add_trust = false;                                   // 是否需要追加信赖干员
    bool m_ignore_requirements = false;                         // 是否跳过未满足的干员属性要求
    std::vector<std::pair<std::string, int>> m_user_additional; // 追加干员表，从头往后加
    DataResource m_data_resource = DataResource::Copilot;
    std::vector<AdditionalFormation> m_additional;
    std::string m_last_oper_name;
    int m_select_formation_index = 0;
    int m_missing_retry_times = 1; // 识别不到干员的重试次数

    // ————————————————————————————————
    // 助战干员选择相关
    // ————————————————————————————————
    using Friendship = battle::Friendship;
    using Role = battle::Role;
    using OperModule = battle::OperModule;
    using RequiredOper = battle::RequiredOper;

    std::optional<std::string> add_support_unit(
        const std::vector<RequiredOper>& required_opers = {},
        size_t max_refresh_times = 5,
        Friendship friendship = Friendship::Stranger);

    std::optional<std::string> add_support_unit_from_support_list(
        SupportList& support_list,
        const std::vector<RequiredOper>& required_opers,
        Friendship friendship = Friendship::Stranger);

    SupportUnitUsage m_support_unit_usage = SupportUnitUsage::None;
    bool m_used_support_unit = false; // 是否已经招募助战干员
    // ———————— 以下变量为指定助战干员设置，仅当 m_support_unit_usage == SupportUnitUsage::Specific 时有效 ————————
    battle::RequiredOper m_specific_support_unit;

private:
    static constexpr battle::Role Roles[] = { battle::Role::Caster,  battle::Role::Medic,   battle::Role::Pioneer,
                                              battle::Role::Warrior, battle::Role::Special, battle::Role::Tank,
                                              battle::Role::Sniper,  battle::Role::Support };
    BattleQuickFormation m_quick_formation_ui;
};
} // namespace asst
