from typing import Generic, Literal, NotRequired, TypedDict

from ldnode.calculator.schemas.enumerations import (
    CBBuiltinScope,
    CBNeutralizationMethod,
    CBProcessMissingDataMethod,
    ETFBuiltinScope,
    ETFNeutralizationMethod,
    ETFProcessMissingDataMethod,
    HoldRangeType,
    HoldWeight,
    SortOrder,
    STKBuiltinScope,
    STKNeutralizationMethod,
    STKProcessMissingDataMethod,
)

from .factor import MMT, NFT, ComputedFactor, ExcludeFactor, RankFactor
from .security_pool import SCOPE, SecurityPool


class HoldRangeValue(TypedDict):
    start: float  # 持有范围开始值
    end: float  # 持有范围结束值


class HoldMethod(TypedDict):
    """持有方式"""

    hold_range_type: HoldRangeType  # 持有范围类型
    hold_range_value: HoldRangeValue  # 持有范围值
    hold_threshold: float  # 持有排名阈值
    hold_weight: HoldWeight  # 持有权重
    max_hold_weight: float  # 个股最大买入仓位


class ExcludeConditionGroup(TypedDict):
    """高级过滤条件组"""

    relation: Literal["AND", "OR"]  # 关系
    conditions: "list[ExcludeFactor | ExcludeConditionGroup]"  # 条件列表

    @staticmethod
    def flatten(group: "ExcludeConditionGroup") -> list[ExcludeFactor]:
        """展开高级过滤条件组"""
        array: list[ExcludeFactor] = []
        for condition in group["conditions"]:
            if condition.get("relation"):
                array.extend(ExcludeConditionGroup.flatten(condition))
            else:
                array.append(condition)

        return array


class ScreenParameters(TypedDict, Generic[NFT, MMT, SCOPE]):
    """选股/债参数"""

    pools: NotRequired[list[SecurityPool[SCOPE]]]  # 标的池

    hold_method: HoldMethod  # 持有方式

    exclude_st: NotRequired[bool]  # 排除ST
    exclude_market: NotRequired[list[str]]  # 排除市场
    exclude_first_industries: NotRequired[list[str]]  # 排除一级行业
    exclude_second_industries: NotRequired[list[str]]  # 排除二级行业
    exclude_third_industries: NotRequired[list[str]]  # 排除三级行业
    exclude_orgform: NotRequired[list[str]]  # 排除组织形式
    exclude_area: NotRequired[list[str]]  # 排除地区
    exclude_ignore_list: NotRequired[list[str]]  # 排除忽略标的列表

    computed_factors: list[list[ComputedFactor]]  # 自定义因子
    filter_factors: ExcludeConditionGroup  # 排除因子
    rank_factors: list[RankFactor[NFT, MMT]]  # 打分因子

    more_by: list[tuple[str, SortOrder]]  # 得分相同时的排序依据


class CBScreenParameters(
    ScreenParameters[CBNeutralizationMethod, CBProcessMissingDataMethod, CBBuiltinScope]
):
    """转债选股/债参数"""

    exclude_call: NotRequired[list[str]]  # 排除强赎
    exclude_list_days: NotRequired[int]  # 排除上市天数
    exclude_rating: NotRequired[list[str]]  # 排除评级
    exclude_yy_rating: NotRequired[list[str]]  # 排除yy评级


class STKScreenParameters(
    ScreenParameters[
        STKNeutralizationMethod, STKProcessMissingDataMethod, STKBuiltinScope
    ]
):
    """股票选股参数"""

    exclude_list_days: NotRequired[int]  # 排除上市天数
    exclude_delisting: NotRequired[bool]  # 排除退整理期股票


class ETFScreenParameters(
    ScreenParameters[
        ETFNeutralizationMethod, ETFProcessMissingDataMethod, ETFBuiltinScope
    ]
):
    """基金选股参数"""
