from __future__ import annotations

import re
from dataclasses import dataclass
from pathlib import Path
from typing import BinaryIO

from openpyxl import load_workbook

from ..core.logger import AppLogger
from ..database.orm import CommissionRecordORM
from ..io.storage import FileStorage
from ..repositories import CommissionRepository, EmployeeRepository

logger = AppLogger.get_logger(__name__)
MONTH_RE = re.compile(r"^\d{4}-\d{2}$")


@dataclass(frozen=True)
class CommissionPage:
    items: list[CommissionRecordORM]
    total: int
    page: int
    page_size: int


class CommissionService:
    """提成应用服务：封装手工维护、Excel导入和月度汇总。"""

    def __init__(
        self,
        repository: CommissionRepository,
        employee_repository: EmployeeRepository,
        storage: FileStorage | None = None,
    ):
        self.repository = repository
        self.employee_repository = employee_repository
        self.storage = storage

    def list_records(
        self,
        *,
        page: int,
        page_size: int,
        commission_month: str | None = None,
        keyword: str | None = None,
    ) -> CommissionPage:
        month = _clean_optional(commission_month)
        if month:
            _validate_month(month)
        items, total = self.repository.list_records(
            page=page,
            page_size=page_size,
            commission_month=month,
            keyword=_clean_optional(keyword),
        )
        logger.info("查询提成记录成功 total=%s page=%s page_size=%s", total, page, page_size)
        return CommissionPage(items=items, total=total, page=page, page_size=page_size)

    def create_record(self, **values) -> CommissionRecordORM:
        values = self._validated_values(values)
        record = self.repository.create_record(**values)
        logger.info("新增提成记录成功 record_id=%s employee_id=%s amount=%s", record.id, record.employee_id, record.amount)
        return record

    def update_record(self, record_id: int, **values) -> CommissionRecordORM:
        values = self._validated_values(values)
        record = self.repository.update_record(record_id, **values)
        logger.info("更新提成记录成功 record_id=%s employee_id=%s amount=%s", record.id, record.employee_id, record.amount)
        return record

    def delete_record(self, record_id: int) -> None:
        self.repository.delete_record(record_id)
        logger.info("删除提成记录成功 record_id=%s", record_id)

    def aggregate_by_employee_id(self, commission_month: str) -> dict[int, float]:
        _validate_month(commission_month)
        return self.repository.aggregate_by_month(commission_month)

    def import_excel(self, filename: str, stream: BinaryIO) -> int:
        if self.storage is None:
            raise ValueError("文件存储未初始化")
        upload_path = self.storage.save_upload(filename, stream)
        count = self._import_from_path(upload_path)
        logger.info("提成Excel导入完成 filename=%s count=%s", filename, count)
        return count

    def _validated_values(self, values: dict) -> dict:
        employee_id = int(values.get("employee_id") or 0)
        self.employee_repository.require_by_id(employee_id)
        commission_month = _normalize_month(str(values.get("commission_month") or "").strip())
        _validate_month(commission_month)
        amount = float(values.get("amount") or 0)
        if amount < 0:
            raise ValueError("提成金额不能小于0")
        return {
            "employee_id": employee_id,
            "commission_month": commission_month,
            "commission_type": str(values.get("commission_type") or "销售提成").strip() or "销售提成",
            "amount": amount,
            "source_type": str(values.get("source_type") or "manual").strip() or "manual",
            "business_ref": str(values.get("business_ref") or "").strip(),
            "remark": str(values.get("remark") or "").strip(),
        }

    def _import_from_path(self, path: Path) -> int:
        workbook = load_workbook(path, data_only=True)
        sheet = workbook.active
        headers = {
            str(sheet.cell(1, col_idx).value or "").strip(): col_idx
            for col_idx in range(1, sheet.max_column + 1)
        }
        required = ("月份", "金额")
        missing = [name for name in required if name not in headers]
        if missing:
            raise ValueError(f"提成导入缺少必要表头：{', '.join(missing)}")

        rows: list[CommissionRecordORM] = []
        for row_idx in range(2, sheet.max_row + 1):
            month = _normalize_month(_cell(sheet, row_idx, headers.get("月份")))
            amount_text = _cell(sheet, row_idx, headers.get("金额"))
            if not month and not amount_text:
                continue
            employee = self._employee_from_row(sheet, row_idx, headers)
            if employee is None:
                raise ValueError(f"第 {row_idx} 行未匹配到员工，请提供员工编号或姓名")
            _validate_month(month)
            amount = float(amount_text or 0)
            if amount < 0:
                raise ValueError(f"第 {row_idx} 行提成金额不能小于0")
            rows.append(
                CommissionRecordORM(
                    employee_id=employee.id,
                    commission_month=month,
                    commission_type=_cell(sheet, row_idx, headers.get("提成类型")) or "销售提成",
                    amount=amount,
                    source_type="excel",
                    business_ref=_cell(sheet, row_idx, headers.get("业务单号")),
                    remark=_cell(sheet, row_idx, headers.get("备注")),
                )
            )
        return self.repository.create_many(rows) if rows else 0

    def _employee_from_row(self, sheet, row_idx: int, headers: dict[str, int]):
        employee_no = _cell(sheet, row_idx, headers.get("员工编号"))
        if employee_no:
            employee = self.employee_repository.get_by_employee_no(employee_no)
            if employee is not None:
                return employee
        name = _cell(sheet, row_idx, headers.get("姓名"))
        if name:
            matches = self.employee_repository.list_employees(keyword=name, employment_status="active")
            exact = [employee for employee in matches if employee.name == name]
            if len(exact) == 1:
                return exact[0]
        return None


def _validate_month(value: str) -> None:
    if not MONTH_RE.match(value):
        raise ValueError("月份格式必须为YYYY-MM")


def _normalize_month(value: str) -> str:
    text = value.strip().replace("/", "-")
    if re.match(r"^\d{4}-\d{2}(-\d{2})?", text):
        return text[:7]
    return text


def _clean_optional(value: str | None) -> str | None:
    if value is None:
        return None
    stripped = value.strip()
    return stripped or None


def _cell(sheet, row_idx: int, col_idx: int | None) -> str:
    if not col_idx:
        return ""
    value = sheet.cell(row_idx, col_idx).value
    return "" if value is None else str(value).strip()
