from __future__ import annotations

from pathlib import Path

from openpyxl import Workbook, load_workbook
from openpyxl.styles import Alignment, Font, PatternFill
from openpyxl.utils import get_column_letter

from ..core.config import AppConfig
from ..domain.models import PayrollResult
from .parser import iter_leave_event_descriptions


SUMMARY_HEADERS = [
    "姓名",
    "部门",
    "职位",
    "考勤组",
    "工资月份",
    "薪资模式",
    "出勤天数",
    "缺勤天数",
    "实际工作工时",
    "休息天数",
    "系统加班总时长",
    "打卡推算加班工时",
    "请假/调休工时",
    "剩余加班工时",
    "工作日加班工时",
    "周末加班工时",
    "节假日加班工时",
    "5分钟内迟到次数",
    "超过5分钟迟到次数",
    "计扣迟到次数",
    "迟到扣款",
    "缺卡次数",
    "缺卡扣款",
    "扣款合计",
    "底薪",
    "模式基础工资",
    "提成",
    "工作日加班单价",
    "周末加班单价",
    "节假日加班单价",
    "加班费",
    "应发工资",
    "实发工资",
    "备注",
]

DAILY_HEADERS = [
    "姓名",
    "日期",
    "原始考勤结果",
    "上班打卡",
    "下班打卡",
    "打卡推算加班工时",
    "迟到分钟",
    "缺卡次数",
    "请假/调休工时(本格)",
    "请假/调休记录",
]

SALARY_MODE_LABELS = {
    "monthly": "包月",
    "hourly": "计时",
    "piecework": "计件",
    "probation": "试用期",
}


def export_payroll_results(results: list[PayrollResult], config: AppConfig, output_path: str | Path) -> Path:
    """导出工资汇总、每日明细和规则说明三张表。"""
    output_path = Path(output_path)
    output_path.parent.mkdir(parents=True, exist_ok=True)

    workbook = Workbook()
    summary_sheet = workbook.active
    summary_sheet.title = "工资汇总"
    daily_sheet = workbook.create_sheet("每日明细")
    rules_sheet = workbook.create_sheet("规则说明")

    _write_summary(summary_sheet, results)
    _write_daily_details(daily_sheet, results)
    _write_rules(rules_sheet, config)

    for sheet in workbook.worksheets:
        _style_sheet(sheet)

    workbook.save(output_path)
    return output_path


def localize_payroll_export_salary_modes(source_path: str | Path, output_path: str | Path) -> Path:
    """复制工资表并把汇总页的薪资模式编码转换为中文标签。"""
    source_path = Path(source_path)
    output_path = Path(output_path)
    output_path.parent.mkdir(parents=True, exist_ok=True)

    workbook = load_workbook(source_path)
    if "工资汇总" in workbook.sheetnames:
        sheet = workbook["工资汇总"]
        salary_mode_column = _find_header_column(sheet, "薪资模式")
        if salary_mode_column is not None:
            for row_idx in range(2, sheet.max_row + 1):
                cell = sheet.cell(row=row_idx, column=salary_mode_column)
                if cell.value is not None:
                    cell.value = _salary_mode_label(str(cell.value))

    workbook.save(output_path)
    return output_path


def _write_summary(sheet, results: list[PayrollResult]) -> None:
    sheet.append(SUMMARY_HEADERS)
    for result in results:
        employee = result.employee
        row = [
            employee.name,
            employee.department,
            employee.position,
            employee.attendance_group,
            result.salary_month,
            _salary_mode_label(result.salary_mode),
            result.attendance_days,
            result.absence_days,
            result.actual_work_hours,
            employee.summary_fields.get("休息天数", 0),
            employee.summary_fields.get("加班总时长", 0),
            result.punch_overtime_hours,
            result.leave_hours,
            result.remaining_overtime_hours,
            result.workday_overtime_hours,
            result.weekend_overtime_hours,
            result.holiday_overtime_hours,
            result.minor_late_count,
            result.major_late_count,
            result.penalized_late_count,
            result.late_deduction,
            result.missing_card_count,
            result.missing_card_deduction,
            result.total_deduction,
            result.base_salary,
            result.base_pay,
            result.commission_amount,
            result.overtime_rate,
            result.weekend_overtime_rate,
            result.holiday_overtime_rate,
            result.overtime_pay,
            result.gross_salary,
            result.net_salary,
            result.note,
        ]
        sheet.append(row)


def _write_daily_details(sheet, results: list[PayrollResult]) -> None:
    sheet.append(DAILY_HEADERS)
    for result in results:
        for record in result.employee.daily_records:
            sheet.append(
                [
                    result.employee.name,
                    record.work_date,
                    record.raw_text,
                    _format_time(record.first_punch),
                    _format_time(record.last_punch),
                    record.punch_overtime_hours,
                    ",".join(str(minutes) for minutes in record.late_minutes),
                    record.missing_card_count,
                    record.leave_hours_in_cell,
                    "；".join(iter_leave_event_descriptions(record.leave_events)),
                ]
            )


def _write_rules(sheet, config: AppConfig) -> None:
    rows = [
        ("下班时间", config.attendance.off_work_time),
        ("加班取整分钟", config.attendance.overtime_round_minutes),
        ("加班计算", "以下班打卡时间为准，超过下班时间后按取整分钟向下取整"),
        ("5分钟内迟到免扣次数", config.attendance.minor_late_free_times),
        ("迟到分钟阈值", config.attendance.minor_late_minutes),
        ("迟到扣款/次", config.attendance.late_penalty),
        ("缺卡扣款/次", config.attendance.missing_card_penalty),
        ("请假/调休关键字", "、".join(config.attendance.leave_keywords)),
        ("剩余加班工时", "打卡推算加班工时 - 去重后的请假/调休工时"),
    ]
    sheet.append(["规则", "值"])
    for row in rows:
        sheet.append(row)


def _style_sheet(sheet) -> None:
    header_fill = PatternFill("solid", fgColor="1F4E78")
    header_font = Font(color="FFFFFF", bold=True)
    for cell in sheet[1]:
        cell.fill = header_fill
        cell.font = header_font
        cell.alignment = Alignment(horizontal="center", vertical="center")

    sheet.freeze_panes = "A2"
    for row in sheet.iter_rows(min_row=2):
        for cell in row:
            cell.alignment = Alignment(vertical="top", wrap_text=True)

    for col_idx, cells in enumerate(sheet.columns, start=1):
        max_length = 0
        for cell in cells:
            value = cell.value
            if value is None:
                continue
            text = str(value)
            max_length = max(max_length, min(len(text), 45))
        sheet.column_dimensions[get_column_letter(col_idx)].width = max(10, max_length + 2)


def _format_time(value) -> str:
    if value is None:
        return ""
    return value.strftime("%H:%M")


def _find_header_column(sheet, header: str) -> int | None:
    for cell in sheet[1]:
        if cell.value == header:
            return cell.column
    return None


def _salary_mode_label(value: str) -> str:
    return SALARY_MODE_LABELS.get(value, value)
