from datetime import date

import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session

from app.api.routes.admin_imports import COL_COURSE_NAME, COL_STAGE_NAME, build_import_template_workbook
from app.db.base import Base
from app.models import Certificate, Learner, ProjectCourse
from app.services.certificate_issuance import CertificateIssueData, DuplicateCertificate, issue_certificate
from app.services.learner_identity import LearnerIdentityConflict, resolve_learner


@pytest.fixture
def db() -> Session:
    engine = create_engine("sqlite+pysqlite:///:memory:")
    Base.metadata.create_all(engine)
    with Session(engine) as session:
        yield session


def add_project(db: Session) -> None:
    db.add(
        ProjectCourse(
            code="DBY",
            name="大本营",
            default_certificate_name="培训结业证书",
            default_course_name="智慧赋能疗愈师",
            default_stage_name="初级",
            default_template_code="classic",
        )
    )
    db.flush()


def test_practice_template_has_only_its_required_certificate_columns():
    sheet = build_import_template_workbook("practice-camp")["证书导入模板"]
    headers = [cell.value for cell in sheet[1]]

    assert headers == ["姓名", "手机号", "项目代码", "课程开始日期", "课程结束日期", "发证日期"]
    assert COL_COURSE_NAME not in headers
    assert COL_STAGE_NAME not in headers


def test_learner_identity_reuses_exact_name_and_phone_but_rejects_name_conflict(db: Session):
    learner, created = resolve_learner(db, "张三", "138-0000-0000", source="test")
    reused, reused_created = resolve_learner(db, "张三", "+86 13800000000", source="test")

    assert created is True
    assert reused_created is False
    assert reused.id == learner.id
    with pytest.raises(LearnerIdentityConflict, match="姓名.*不一致"):
        resolve_learner(db, "李四", "13800000000", source="test")


def test_one_learner_can_hold_multiple_template_certificates(db: Session):
    add_project(db)
    common = dict(
        learner_name="张三",
        learner_phone="13800000000",
        project_code="DBY",
        course_start_date=date(2026, 3, 1),
        course_end_date=date(2026, 8, 31),
    )
    classic, _, classic_created = issue_certificate(
        db,
        CertificateIssueData(
            **common,
            template_code="classic",
            issue_date=date(2026, 9, 5),
            course_name="智慧赋能疗愈师",
            stage_name="初级",
        ),
        source="test",
    )
    practice, _, practice_created = issue_certificate(
        db,
        CertificateIssueData(
            **common,
            template_code="practice-camp",
            issue_date=date(2026, 9, 6),
        ),
        source="test",
    )

    assert classic_created is True
    assert practice_created is False
    assert classic.learner_id == practice.learner_id
    assert db.query(Learner).count() == 1
    assert db.query(Certificate).count() == 2
    assert practice.course_name is None
    assert practice.stage_name is None


def test_duplicate_certificate_is_rejected(db: Session):
    add_project(db)
    data = CertificateIssueData(
        learner_name="张三",
        learner_phone="13800000000",
        project_code="DBY",
        template_code="practice-camp",
        course_start_date=date(2026, 3, 1),
        course_end_date=date(2026, 8, 31),
        issue_date=date(2026, 9, 5),
    )
    issue_certificate(db, data, source="test")

    with pytest.raises(DuplicateCertificate):
        issue_certificate(db, data, source="test")
