from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal
from typing import Any

from market_api.award.common import (
    build_ct_filter,
    format_pp_change,
    format_share,
    format_wan_amount,
)
from market_api.db.sql import qualify_table, quote_identifier
from market_api.tender.common import build_scope_filter, normalize_month


OPERATORS = ("移动", "电信", "联通")
OPERATOR_AMOUNT_COLUMNS = {
    "移动": "移动金额_万元",
    "电信": "电信金额_万元",
    "联通": "联通金额_万元",
}


@dataclass(frozen=True)
class AwardOperatorAggregate:
    count: int
    amount_wan: Decimal


class AwardOverallRepository:
    def __init__(self, conn: Any, schema: str):
        self.conn = conn
        self.schema = schema

    def aggregate(
        self,
        year: int,
        months: list[int],
        ct_filter: tuple[str, ...],
        scope_filter: tuple[str, str] | None,
    ) -> dict[str, AwardOperatorAggregate]:
        if not months:
            raise ValueError("统计月份不能为空")

        month_placeholders = ", ".join(["%s"] * len(months))
        where_parts = [
            f"{quote_identifier('年份')} = %s",
            f"{quote_identifier('月份')} IN ({month_placeholders})",
        ]
        params: list[object] = [year, *[f"{month}月" for month in months]]

        ct_value = ct_filter[0]
        ct_column = quote_identifier("CT类")
        if ct_value == "是":
            where_parts.append(f"{ct_column} IS NOT NULL")
            where_parts.append(f"{ct_column} <> %s")
            params.append("")
        else:
            where_parts.append(f"{ct_column} = %s")
            params.append("否")

        if scope_filter is not None:
            column_name, scope_value = scope_filter
            where_parts.append(f"{quote_identifier(column_name)} = %s")
            params.append(scope_value)

        select_parts: list[str] = []
        for operator in OPERATORS:
            amount_column = quote_identifier(OPERATOR_AMOUNT_COLUMNS[operator])
            select_parts.append(f"COUNT({amount_column})")
            select_parts.append(f"COALESCE(SUM({amount_column}), 0)")

        sql = (
            f"SELECT {', '.join(select_parts)} "
            f"FROM {qualify_table(self.schema, '运营商市场中标数据')} "
            f"WHERE {' AND '.join(where_parts)}"
        )

        with self.conn.cursor() as cursor:
            cursor.execute(sql, params)
            row = cursor.fetchone()

        if row is None:
            row = (0, Decimal("0"), 0, Decimal("0"), 0, Decimal("0"))

        return {
            operator: AwardOperatorAggregate(
                int(row[index * 2] or 0),
                Decimal(str(row[index * 2 + 1] or 0)),
            )
            for index, operator in enumerate(OPERATORS)
        }


def _operator_share(value: Decimal | int, total: Decimal | int) -> Decimal | None:
    total_value = Decimal(str(total))
    if total_value == 0:
        return None
    return Decimal(str(value)) / total_value * Decimal("100")


def _empty_aggregate() -> AwardOperatorAggregate:
    return AwardOperatorAggregate(0, Decimal("0"))


def _operator_rows(
    current_by_operator: dict[str, AwardOperatorAggregate],
    baseline_by_operator: dict[str, AwardOperatorAggregate] | None,
    count_key: str,
    amount_key: str,
    count_change_key: str,
    amount_change_key: str,
) -> list[dict[str, object]]:
    current_total_count = sum(
        current_by_operator.get(operator, _empty_aggregate()).count
        for operator in OPERATORS
    )
    current_total_amount = sum(
        current_by_operator.get(operator, _empty_aggregate()).amount_wan
        for operator in OPERATORS
    )
    baseline_total_count = (
        None
        if baseline_by_operator is None
        else sum(
            baseline_by_operator.get(operator, _empty_aggregate()).count
            for operator in OPERATORS
        )
    )
    baseline_total_amount = (
        None
        if baseline_by_operator is None
        else sum(
            baseline_by_operator.get(operator, _empty_aggregate()).amount_wan
            for operator in OPERATORS
        )
    )

    rows: list[dict[str, object]] = []
    for operator in OPERATORS:
        current = current_by_operator.get(operator, _empty_aggregate())
        current_count_share = _operator_share(current.count, current_total_count)
        current_amount_share = _operator_share(current.amount_wan, current_total_amount)

        if baseline_by_operator is None:
            baseline_count_share = None
            baseline_amount_share = None
        else:
            baseline = baseline_by_operator.get(operator, _empty_aggregate())
            baseline_count_share = _operator_share(baseline.count, baseline_total_count or 0)
            baseline_amount_share = _operator_share(
                baseline.amount_wan,
                baseline_total_amount or 0,
            )

        rows.append(
            {
                "运营商": operator,
                count_key: current.count,
                amount_key: format_wan_amount(current.amount_wan),
                "个数份额": format_share(current_count_share),
                "金额份额": format_share(current_amount_share),
                count_change_key: format_pp_change(
                    current_count_share,
                    baseline_count_share,
                ),
                amount_change_key: format_pp_change(
                    current_amount_share,
                    baseline_amount_share,
                ),
            }
        )
    return rows


def build_award_overall_summary(
    repository: object,
    year: int,
    month: str | int,
    ct: str,
    scope: str,
    scope_value: str | None,
) -> dict[str, object]:
    month_number = normalize_month(month)
    ct_filter = build_ct_filter(ct)
    normalized_ct = ct_filter[0]
    normalized_scope_value = scope_value.strip() if scope_value is not None else None
    scope_filter = build_scope_filter(scope, normalized_scope_value)

    cumulative_months = list(range(1, month_number + 1))
    current_cumulative = repository.aggregate(
        year,
        cumulative_months,
        ct_filter,
        scope_filter,
    )
    baseline_cumulative = repository.aggregate(
        year - 1,
        cumulative_months,
        ct_filter,
        scope_filter,
    )
    current_monthly = repository.aggregate(year, [month_number], ct_filter, scope_filter)

    if month_number == 1:
        previous_monthly = None
    else:
        previous_monthly = repository.aggregate(
            year,
            [month_number - 1],
            ct_filter,
            scope_filter,
        )

    return {
        "统计年份": year,
        "统计月份": f"{month_number}月",
        "统计CT": normalized_ct,
        "统计方式": scope,
        "统计参数": normalized_scope_value if scope != "上海" else None,
        "累计数据": _operator_rows(
            current_cumulative,
            baseline_cumulative,
            "累计中标个数",
            "累计中标金额（万元）",
            "个数份额同比变化（百分点）",
            "金额份额同比变化（百分点）",
        ),
        "月度数据": _operator_rows(
            current_monthly,
            previous_monthly,
            "单月中标个数",
            "单月中标金额（万元）",
            "个数份额环比变化（百分点）",
            "金额份额环比变化（百分点）",
        ),
    }
