"""Unit tests for intern_daily_report.py"""

from __future__ import annotations

import sys
from datetime import date
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent))

from intern_daily_report import (
    find_roster_file,
    parse_roster_table,
    parse_daily_entries,
    parse_leave_table,
    is_date_in_leave_range,
    judge_status,
    format_report,
)


# ── Fixtures ──────────────────────────────────────────────────

@pytest.fixture
def roster_md():
    return """# 实习生列表

### 1. 实习生维度

| 序号 | 姓名 | 入职日期 | 工位 | 实习生Base | 实际导师 | 挂职导师 | 导师Base | 挂职导师Base | 所属PDT | 备注 |
|------|------|----------|------|------------|----------|----------|----------|--------------|--------|------|
| 1 | 张三 | 2026/05/01 | 2#3F-001 | 北京 | 李四 | 李四 | 北京 | 北京 | 场景PDT | |
| 2 | 王五 | 2026/06/01 | 2#3F-002 | 北京 | 赵六 | 赵六 | 北京 | 北京 | 架构PDT | |
| 3 | 钱七 | 2026/07/01 | 2#3F-003 | 北京 | 孙八 | 孙八 | 北京 | 北京 | | |
| 4 | 已走的人 | 2026/05/01 | 2#3F-004 | 北京 | 某某 | 某某 | 北京 | 北京 | 场景PDT | ⚠️ 已离职 |
| 5 | 放弃的人 | 2026/05/01 | 2#3F-005 | 北京 | 某某 | 某某 | 北京 | 北京 | 架构PDT | ⚠️ 放弃入职 |
| 6 | 待定的人 | 待定 | 待分配 | 北京 | 某某 | 某某 | 北京 | 北京 | | |
"""


@pytest.fixture
def roster_file(roster_md, tmp_path):
    d = tmp_path / "memory"
    d.mkdir()
    f = d / "实习生信息表-v2.0.0.md"
    f.write_text(roster_md, encoding="utf-8")
    return str(d)


@pytest.fixture
def daily_md():
    return """
---
### 收到时间：2026-06-04 18:00（Asia/Shanghai）
- **类型：** 日报
- **原始正文（原文摘录）**
姓名：张三
今天主要工作：修复自动化测试bug
当前进度：已完成
是否存在卡点：否
下一步计划：继续推进测试
"""


@pytest.fixture
def daily_file(daily_md, tmp_path):
    d = tmp_path / "records"
    d.mkdir(parents=True)
    f = d / "2026-06-04.md"
    f.write_text(daily_md, encoding="utf-8")
    return d


@pytest.fixture
def leave_md():
    return """## 2026-06

| 报备日期 | 姓名 | 导师 | 请假时间 | 备注 |
|----------|------|------|----------|------|
| 2026-06-01 | 王五 | 赵六 | 2026-06-04～2026-06-05 | 回学校考试，OA 已提交 |
| 2026-06-02 | 钱七 | 孙八 | 2026-06-04（下午） | 开会 |
"""


@pytest.fixture
def leave_file(leave_md, tmp_path):
    d = tmp_path / "records"
    d.mkdir(parents=True)
    f = d / "leave.md"
    f.write_text(leave_md, encoding="utf-8")
    return d


# ── Roster Parsing Tests ─────────────────────────────────────

class TestRosterParsing:
    def test_find_roster_file(self, roster_file):
        path = find_roster_file(roster_file)
        assert path.name.startswith("实习生信息表-")

    def test_find_roster_file_not_found(self):
        with pytest.raises(SystemExit):
            find_roster_file("/nonexistent/path")

    def test_parse_active_interns(self, roster_file):
        path = find_roster_file(roster_file)
        interns = parse_roster_table(path)
        names = [i["name"] for i in interns]
        assert "张三" in names
        assert "王五" in names
        assert "钱七" in names

    def test_exclude_resigned(self, roster_file):
        path = find_roster_file(roster_file)
        interns = parse_roster_table(path)
        names = [i["name"] for i in interns]
        assert "已走的人" not in names

    def test_exclude_abandoned(self, roster_file):
        path = find_roster_file(roster_file)
        interns = parse_roster_table(path)
        names = [i["name"] for i in interns]
        assert "放弃的人" not in names

    def test_empty_pdt_defaults(self, roster_file):
        path = find_roster_file(roster_file)
        interns = parse_roster_table(path)
        qianqi = [i for i in interns if i["name"] == "钱七"][0]
        assert qianqi["pdt"] == "未分配PDT"

    def test_tbd_date_is_none(self, roster_file):
        path = find_roster_file(roster_file)
        interns = parse_roster_table(path)
        daiding = [i for i in interns if i["name"] == "待定的人"][0]
        assert daiding["start_date"] is None


# ── Daily Parsing Tests ──────────────────────────────────────

class TestDailyParsing:
    def test_parse_daily_entries(self, daily_file):
        daily = parse_daily_entries(daily_file / "2026-06-04.md")
        assert "张三" in daily
        assert "修复自动化测试bug" in daily["张三"]["summary"]
        assert daily["张三"]["blocker"] == "否"
        assert "继续推进测试" in daily["张三"]["next_step"]

    def test_parse_nonexistent_file(self, tmp_path):
        daily = parse_daily_entries(tmp_path / "2026-06-99.md")
        assert daily == {}


# ── Leave Parsing Tests ──────────────────────────────────────

class TestLeaveParsing:
    def test_parse_leave_table(self, leave_file):
        leaves = parse_leave_table(leave_file / "leave.md")
        names = [lv["name"] for lv in leaves]
        assert "王五" in names
        assert "钱七" in names

    def test_parse_nonexistent_file(self, tmp_path):
        leaves = parse_leave_table(tmp_path / "leave.md")
        assert leaves == []


# ── Leave Date Coverage Tests ────────────────────────────────

class TestLeaveDateCoverage:
    def test_range_covers_middle(self):
        assert is_date_in_leave_range(date(2026, 6, 4), "2026-06-04～2026-06-05")

    def test_range_covers_start(self):
        assert is_date_in_leave_range(date(2026, 6, 3), "2026-06-03～2026-06-05")

    def test_range_covers_end(self):
        assert is_date_in_leave_range(date(2026, 6, 5), "2026-06-03～2026-06-05")

    def test_range_excludes_before(self):
        assert not is_date_in_leave_range(date(2026, 6, 2), "2026-06-03～2026-06-05")

    def test_range_excludes_after(self):
        assert not is_date_in_leave_range(date(2026, 6, 6), "2026-06-03～2026-06-05")

    def test_single_date_matches(self):
        assert is_date_in_leave_range(date(2026, 6, 4), "2026-06-04（下午）")

    def test_expired_leave_not_covered(self):
        assert not is_date_in_leave_range(date(2026, 6, 14), "2026-05-12")

    def test_empty_string(self):
        assert not is_date_in_leave_range(date(2026, 6, 4), "")


# ── Status Judgment Tests ────────────────────────────────────

class TestJudgeStatus:
    def test_submitted(self):
        entry = {"name": "张三", "pdt": "场景PDT", "start_date": date(2026, 5, 1)}
        daily = {"张三": {"summary": "修bug", "blocker": "否", "next_step": "测试", "ts": ""}}
        status, detail = judge_status(entry, daily, [], date(2026, 6, 4))
        assert status == "submitted"
        assert detail["summary"] == "修bug"

    def test_on_leave(self):
        entry = {"name": "王五", "pdt": "架构PDT", "start_date": date(2026, 6, 1)}
        leaves = [{"name": "王五", "leave_time": "2026-06-04～2026-06-05", "reason": "考试"}]
        status, detail = judge_status(entry, {}, leaves, date(2026, 6, 4))
        assert status == "on_leave"
        assert detail["reason"] == "考试"

    def test_missing(self):
        entry = {"name": "钱七", "pdt": "架构PDT", "start_date": date(2026, 6, 1)}
        status, detail = judge_status(entry, {}, [], date(2026, 6, 4))
        assert status == "missing"

    def test_not_onboarded_future_date(self):
        entry = {"name": "新人", "pdt": "场景PDT", "start_date": date(2026, 7, 1)}
        status, detail = judge_status(entry, {}, [], date(2026, 6, 4))
        assert status == "not_onboarded"

    def test_not_onboarded_none_date(self):
        entry = {"name": "待定", "pdt": "场景PDT", "start_date": None}
        status, detail = judge_status(entry, {}, [], date(2026, 6, 4))
        assert status == "not_onboarded"

    def test_today_onboard_marked(self):
        entry = {"name": "新人", "pdt": "场景PDT", "start_date": date(2026, 6, 4)}
        status, detail = judge_status(entry, {}, [], date(2026, 6, 4))
        assert status == "missing"
        assert detail["is_today_onboard"] is True


# ── Format Report Tests ──────────────────────────────────────

class TestFormatReport:
    def test_format_output_contains_pdt_groups(self):
        roster = [
            {"name": "张三", "pdt": "场景PDT", "start_date": date(2026, 5, 1)},
            {"name": "王五", "pdt": "架构PDT", "start_date": date(2026, 6, 1)},
            {"name": "钱七", "pdt": "架构PDT", "start_date": date(2026, 6, 1)},
        ]
        daily = {"张三": {"summary": "修bug", "blocker": "否", "next_step": "测试", "ts": ""}}
        leaves = [{"name": "王五", "leave_time": "2026-06-04", "reason": "考试", "report_date": "2026-06-01"}]
        report = format_report(roster, daily, leaves, date(2026, 6, 4))
        assert "## 场景PDT" in report
        assert "## 架构PDT" in report
        assert "✅" in report
        assert "🏖️" in report
        assert "❌" in report

    def test_today_onboard_tag(self):
        roster = [
            {"name": "新人", "pdt": "场景PDT", "start_date": date(2026, 6, 4)},
        ]
        report = format_report(roster, {}, [], date(2026, 6, 4))
        assert "🆕" in report

    def test_missing_reminder(self):
        roster = [
            {"name": "张三", "pdt": "场景PDT", "mentor": "李四", "start_date": date(2026, 5, 1)},
            {"name": "王五", "pdt": "架构PDT", "mentor": "赵六", "start_date": date(2026, 6, 1)},
        ]
        report = format_report(roster, {}, [], date(2026, 6, 4))
        assert "⚠️ **未提交提醒：**" in report
        assert "@李四：张三" in report
        assert "@赵六：王五" in report

    def test_missing_reminder_skips_no_mentor(self):
        roster = [
            {"name": "张三", "pdt": "场景PDT", "start_date": date(2026, 5, 1)},
        ]
        report = format_report(roster, {}, [], date(2026, 6, 4))
        assert "⚠️" not in report  # No mentor → no reminder

    def test_missing_reminder_skips_when_all_submitted(self):
        roster = [
            {"name": "张三", "pdt": "场景PDT", "mentor": "李四", "start_date": date(2026, 5, 1)},
        ]
        daily = {"张三": {"summary": "修bug", "blocker": "否", "next_step": "测试", "ts": ""}}
        report = format_report(roster, daily, [], date(2026, 6, 4))
        assert "⚠️" not in report  # All submitted → no reminder
