from __future__ import annotations

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

from market_api.db.sql import qualify_table, quote_identifier
from market_api.tender.classification import ENTERPRISE_CATEGORY, GOVERNMENT_CATEGORY
from market_api.tender.common import build_scope_filter, format_yi_yuan, normalize_month


CATEGORY_COLUMNS = {
    GOVERNMENT_CATEGORY: "政府侧招采金额（亿元）",
    ENTERPRISE_CATEGORY: "企业侧招采金额（亿元）",
}


@dataclass(frozen=True)
class QuarterPeriod:
    year: int
    quarter: int

    @property
    def months(self) -> list[int]:
        start_month = (self.quarter - 1) * 3 + 1
        return [start_month, start_month + 1, start_month + 2]

    @property
    def label(self) -> str:
        return f"{self.year}年{self.quarter}季度"


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

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

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

        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)

        sql = (
            f"SELECT {category_column}, "
            f"COALESCE(SUM({quote_identifier('预算金额_万元')}), 0) AS amount_wan "
            f"FROM {qualify_table(self.schema, '公开市场招标数据')} "
            f"WHERE {' AND '.join(where_parts)} "
            f"GROUP BY {category_column}"
        )

        with self.conn.cursor() as cursor:
            cursor.execute(sql, params)
            rows = cursor.fetchall()

        return {str(category): Decimal(str(amount_wan or 0)) for category, amount_wan in rows}


def build_recent_completed_quarters(
    year: int,
    month: str | int,
    count: int = 5,
) -> list[QuarterPeriod]:
    if count <= 0:
        raise ValueError("统计季度数量必须大于 0")

    month_number = normalize_month(month)
    latest_quarter = month_number // 3
    latest_year = year
    if latest_quarter == 0:
        latest_year -= 1
        latest_quarter = 4

    quarters: list[QuarterPeriod] = []
    for offset in range(count):
        quarter_index = (latest_year * 4 + latest_quarter - 1) - offset
        quarter_year = quarter_index // 4
        quarter = quarter_index % 4 + 1
        quarters.append(QuarterPeriod(quarter_year, quarter))
    return list(reversed(quarters))


def _quarter_row(
    period: QuarterPeriod,
    amounts_by_category: dict[str, Decimal],
) -> dict[str, object]:
    row: dict[str, object] = {"季度": period.label}
    for category, column_name in CATEGORY_COLUMNS.items():
        row[column_name] = format_yi_yuan(amounts_by_category.get(category, Decimal("0")))
    return row


def build_tender_time_summary(
    repository: object,
    year: int,
    month: str | int,
    scope: str,
    scope_value: str | None,
) -> dict[str, object]:
    month_number = normalize_month(month)
    normalized_scope_value = scope_value.strip() if scope_value is not None else None
    scope_filter = build_scope_filter(scope, normalized_scope_value)
    quarters = build_recent_completed_quarters(year, month_number)

    return {
        "统计年份": year,
        "统计月份": f"{month_number}月",
        "统计方式": scope,
        "统计参数": normalized_scope_value if scope != "上海" else None,
        "季度数据": [
            _quarter_row(
                quarter,
                repository.aggregate_by_category(quarter.year, quarter.months, scope_filter),
            )
            for quarter in quarters
        ],
    }
