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 (
    TenderAggregate,
    build_scope_filter,
    format_yi_yuan,
    normalize_month,
)


CATEGORY_COLUMNS = {
    GOVERNMENT_CATEGORY: ("政府侧招标次数", "政府侧招标预算金额（亿元）"),
    ENTERPRISE_CATEGORY: ("企业侧招标次数", "企业侧招标预算金额（亿元）"),
}


@dataclass(frozen=True)
class MonthPeriod:
    year: int
    month: int

    @property
    def label(self) -> str:
        return f"{self.year}年{self.month}月"


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

    def aggregate_by_category(
        self,
        year: int,
        month: int,
        scope_filter: tuple[str, str] | None,
    ) -> dict[str, TenderAggregate]:
        categories = tuple(CATEGORY_COLUMNS)
        category_placeholders = ", ".join(["%s"] * len(categories))
        category_column = quote_identifier("分类")
        where_parts = [
            f"{quote_identifier('年份')} = %s",
            f"{quote_identifier('月份')} = %s",
            f"{category_column} IN ({category_placeholders})",
        ]
        params: list[object] = [year, f"{month}月", *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}, COUNT(*) AS tender_count, "
            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): TenderAggregate(int(count or 0), Decimal(str(amount_wan or 0)))
            for category, count, amount_wan in rows
        }


def build_recent_months(year: int, month: str | int, count: int = 3) -> list[MonthPeriod]:
    if count <= 0:
        raise ValueError("统计月份数量必须大于 0")

    month_number = normalize_month(month)
    current_index = year * 12 + month_number - 1
    periods: list[MonthPeriod] = []
    for offset in range(count - 1, -1, -1):
        month_index = current_index - offset
        period_year = month_index // 12
        period_month = month_index % 12 + 1
        periods.append(MonthPeriod(period_year, period_month))
    return periods


def _month_row(
    period: MonthPeriod,
    aggregates_by_category: dict[str, TenderAggregate],
) -> dict[str, object]:
    row: dict[str, object] = {"月份": period.label}
    for category, (count_column, amount_column) in CATEGORY_COLUMNS.items():
        aggregate = aggregates_by_category.get(category, TenderAggregate(0, Decimal("0")))
        row[count_column] = aggregate.count
        row[amount_column] = format_yi_yuan(aggregate.amount_wan)
    return row


def build_class_trend_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)
    periods = build_recent_months(year, month_number)

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