from dataclasses import dataclass
from datetime import UTC, datetime, timedelta
from hashlib import sha256

from zbt.core.config import Settings
from zbt.core.passwords import PasswordService
from zbt.domains.attribution.models import PromotionCode, Salesperson
from zbt.domains.catalog.models import Plan, Product, ProductChangeLog, ProductVersion
from zbt.domains.identity.models import AdminUser
from zbt.infrastructure.mysql.attribution_repositories import (
    SqlAlchemyAttributionRepository,
)
from zbt.infrastructure.mysql.repositories import (
    SqlAlchemyCatalogRepository,
    SqlAlchemyIdentityRepository,
)
from zbt.infrastructure.mysql.sessions import (
    DatabaseName,
    create_mysql_engine,
    create_session_factory,
)

INITIAL_ADMIN_PASSWORD = "zaq1XSW@"


@dataclass(frozen=True, slots=True)
class SeedManifest:
    admin_users: tuple[AdminUser, ...]
    products: tuple[Product, ...]
    versions: tuple[ProductVersion, ...]
    salespersons: tuple[Salesperson, ...]
    promotion_codes: tuple[PromotionCode, ...]


@dataclass(frozen=True, slots=True)
class PlanConfig:
    summary: str
    premium_cents: int
    coverage_amount_cents: int
    min_age: int
    max_age: int


def stable_id(value: str) -> str:
    return sha256(value.encode("utf-8")).hexdigest()[:26].upper()


def build_seed_manifest(password_hash: str = "HASHED_DURING_DATABASE_SEED") -> SeedManifest:
    products = (
        _product("MED-BASIC", "蓉惠基础医疗险", "MEDICAL"),
        _product("MED-UPGRADE", "蓉惠升级医疗险", "MEDICAL"),
        _product("MED-SENIOR", "银龄守护医疗险", "MEDICAL"),
        _product("ACC-FAMILY", "家庭意外保障险", "ACCIDENT"),
    )
    product_ids = {product.product_code: product.id for product in products}
    versions = (
        _version(product_ids, "MED-BASIC", "1.0.0", "EXPIRED", 2023, 2024, ("BASIC",)),
        _version(product_ids, "MED-BASIC", "2.0.0", "PUBLISHED", 2025, 2029, ("BASIC",)),
        _version(product_ids, "MED-BASIC", "3.0.0", "DRAFT", 2030, None, ("BASIC",)),
        _version(
            product_ids,
            "MED-UPGRADE",
            "1.0.0",
            "PUBLISHED",
            2025,
            2029,
            ("STANDARD", "ENHANCED"),
        ),
        _version(
            product_ids,
            "MED-UPGRADE",
            "1.1.0",
            "DRAFT",
            2030,
            None,
            ("STANDARD", "ENHANCED"),
        ),
        _version(
            product_ids,
            "MED-SENIOR",
            "1.0.0",
            "PUBLISHED",
            2025,
            2029,
            ("SENIOR_STANDARD",),
        ),
        _version(
            product_ids,
            "ACC-FAMILY",
            "1.0.0",
            "PUBLISHED",
            2025,
            2029,
            ("INDIVIDUAL", "FAMILY"),
        ),
    )
    admin_users = (
        _admin("admin", "超级管理员", "SUPER_ADMIN", "ALL", ("*",), password_hash),
        _admin(
            "operator01",
            "运营人员",
            "OPERATOR",
            "MASKED_ALL",
            (
                "dashboard:read",
                "order:read",
                "policy:read",
                "user:read",
                "knowledge:read",
                "knowledge:write",
                "knowledge:publish",
                "service:read",
                "service:review",
            ),
            password_hash,
        ),
        _admin(
            "reviewer01",
            "审核人员",
            "REVIEWER",
            "READ_ONLY",
            (
                "order:read",
                "policy:read",
                "knowledge:read",
                "service:read",
                "service:review",
            ),
            password_hash,
        ),
        _admin(
            "sales_a",
            "张伟",
            "SALESPERSON",
            "SELF",
            (
                "dashboard:read",
                "order:read",
                "policy:read",
                "product:read",
                "attribution:read",
            ),
            password_hash,
        ),
        _admin(
            "sales_b",
            "李娜",
            "SALESPERSON",
            "SELF",
            (
                "dashboard:read",
                "order:read",
                "policy:read",
                "product:read",
                "attribution:read",
            ),
            password_hash,
        ),
        _admin(
            "sales_c",
            "王磊",
            "SALESPERSON",
            "SELF",
            (
                "dashboard:read",
                "order:read",
                "policy:read",
                "product:read",
                "attribution:read",
            ),
            password_hash,
        ),
        _admin(
            "sales_d",
            "陈晨",
            "SALESPERSON",
            "SELF",
            (
                "dashboard:read",
                "order:read",
                "policy:read",
                "product:read",
                "attribution:read",
            ),
            password_hash,
        ),
        _admin(
            "sales_e",
            "刘洋",
            "SALESPERSON",
            "SELF",
            (
                "dashboard:read",
                "order:read",
                "policy:read",
                "product:read",
                "attribution:read",
            ),
            password_hash,
        ),
        _admin(
            "sales_f",
            "赵敏",
            "SALESPERSON",
            "SELF",
            (
                "dashboard:read",
                "order:read",
                "policy:read",
                "product:read",
                "attribution:read",
            ),
            password_hash,
        ),
    )
    created_at = datetime(2026, 1, 1, tzinfo=UTC)
    salespersons = (
        Salesperson(
            id=stable_id("salesperson:sales_a"),
            admin_user_id=stable_id("admin:sales_a"),
            code="SALES-A",
            name="张伟",
            status="ACTIVE",
            created_at=created_at,
        ),
        Salesperson(
            id=stable_id("salesperson:sales_b"),
            admin_user_id=stable_id("admin:sales_b"),
            code="SALES-B",
            name="李娜",
            status="ACTIVE",
            created_at=created_at,
        ),
        Salesperson(
            id=stable_id("salesperson:sales_c"),
            admin_user_id=stable_id("admin:sales_c"),
            code="SALES-C",
            name="王磊",
            status="ACTIVE",
            created_at=created_at,
        ),
        Salesperson(
            id=stable_id("salesperson:sales_d"),
            admin_user_id=stable_id("admin:sales_d"),
            code="SALES-D",
            name="陈晨",
            status="ACTIVE",
            created_at=created_at,
        ),
        Salesperson(
            id=stable_id("salesperson:sales_e"),
            admin_user_id=stable_id("admin:sales_e"),
            code="SALES-E",
            name="刘洋",
            status="ACTIVE",
            created_at=created_at,
        ),
        Salesperson(
            id=stable_id("salesperson:sales_f"),
            admin_user_id=stable_id("admin:sales_f"),
            code="SALES-F",
            name="赵敏",
            status="ACTIVE",
            created_at=created_at,
        ),
    )
    promotion_codes = (
        PromotionCode(
            id=stable_id("promotion:ZBT-SALES-A"),
            code="ZBT-SALES-A",
            salesperson_id=salespersons[0].id,
            channel="GROUND_PROMOTION",
            status="ACTIVE",
            created_at=created_at,
        ),
        PromotionCode(
            id=stable_id("promotion:ZBT-SALES-B"),
            code="ZBT-SALES-B",
            salesperson_id=salespersons[1].id,
            channel="COMMUNITY",
            status="ACTIVE",
            created_at=created_at,
        ),
        PromotionCode(
            id=stable_id("promotion:ZBT-SALES-C"),
            code="ZBT-SALES-C",
            salesperson_id=salespersons[2].id,
            channel="ENTERPRISE",
            status="ACTIVE",
            created_at=created_at,
        ),
        PromotionCode(
            id=stable_id("promotion:ZBT-SALES-D"),
            code="ZBT-SALES-D",
            salesperson_id=salespersons[3].id,
            channel="PARTNER",
            status="ACTIVE",
            created_at=created_at,
        ),
        PromotionCode(
            id=stable_id("promotion:ZBT-SALES-E"),
            code="ZBT-SALES-E",
            salesperson_id=salespersons[4].id,
            channel="ONLINE_REFERRAL",
            status="ACTIVE",
            created_at=created_at,
        ),
        PromotionCode(
            id=stable_id("promotion:ZBT-SALES-F"),
            code="ZBT-SALES-F",
            salesperson_id=salespersons[5].id,
            channel="STORE",
            status="ACTIVE",
            created_at=created_at,
        ),
    )
    return SeedManifest(
        admin_users=admin_users,
        products=products,
        versions=versions,
        salespersons=salespersons,
        promotion_codes=promotion_codes,
    )


def run_seed(settings: Settings | None = None) -> SeedManifest:
    resolved_settings = settings or Settings()
    password_hash = PasswordService().hash(INITIAL_ADMIN_PASSWORD)
    manifest = build_seed_manifest(password_hash)
    engine = create_mysql_engine(resolved_settings, DatabaseName.CORE)
    factory = create_session_factory(engine)
    identities = SqlAlchemyIdentityRepository(factory)
    catalog = SqlAlchemyCatalogRepository(factory)
    attribution = SqlAlchemyAttributionRepository(factory)
    for admin_user in manifest.admin_users:
        identities.save_admin_user(admin_user)
    for product in manifest.products:
        catalog.save_product(product)
    for version in manifest.versions:
        catalog.save_version(version)
    audit_anchor = datetime(2026, 7, 1, 9, 0, tzinfo=UTC)
    for index, product in enumerate(manifest.products):
        catalog.save_change_log(
            ProductChangeLog(
                id=stable_id(f"product-log:created:{product.id}"),
                product_id=product.id,
                version_id=None,
                action="PRODUCT_CREATED",
                actor_id="SYSTEM",
                actor_name="系统初始化",
                detail={"product_code": product.product_code},
                created_at=audit_anchor - timedelta(days=120 - index),
            )
        )
    for index, version in enumerate(manifest.versions):
        catalog.save_change_log(
            ProductChangeLog(
                id=stable_id(f"product-log:version:{version.id}"),
                product_id=version.product_id,
                version_id=version.id,
                action=(
                    "VERSION_DRAFT_CREATED"
                    if version.status == "DRAFT"
                    else "VERSION_IMPORTED"
                ),
                actor_id="SYSTEM",
                actor_name="系统初始化",
                detail={"version_no": version.version_no, "status": version.status},
                created_at=audit_anchor - timedelta(days=40 - index * 3),
            )
        )
    for salesperson in manifest.salespersons:
        attribution.save_salesperson(salesperson)
    for promotion_code in manifest.promotion_codes:
        attribution.save_promotion_code(promotion_code)
    engine.dispose()
    return manifest


def _product(code: str, name: str, category: str) -> Product:
    summaries = {
        "MED-BASIC": "覆盖常见住院医疗费用，为年轻家庭提供简洁实用的基础保障。",
        "MED-UPGRADE": "提高医疗费用保障额度，并提供标准与升级两档方案灵活选择。",
        "MED-SENIOR": "面向中老年人群的住院医疗保障，覆盖50至75周岁的投保需求。",
        "ACC-FAMILY": "覆盖日常意外风险，可按个人或家庭方案为家人统一配置保障。",
    }
    return Product(
        id=stable_id(f"product:{code}"),
        product_code=code,
        name=name,
        category=category,
        summary=summaries[code],
        status="ACTIVE",
    )


def _version(
    product_ids: dict[str, str],
    product_code: str,
    version_no: str,
    status: str,
    start_year: int,
    end_year: int | None,
    plan_codes: tuple[str, ...],
) -> ProductVersion:
    version_key = f"{product_code}:{version_no}"
    return ProductVersion(
        id=stable_id(f"version:{version_key}"),
        product_id=product_ids[product_code],
        version_no=version_no,
        status=status,
        effective_from=datetime(start_year, 1, 1, tzinfo=UTC),
        effective_to=(
            datetime(end_year, 12, 31, 23, 59, 59, tzinfo=UTC) if end_year is not None else None
        ),
        terms_summary=(
            "本产品为一年期保障，等待期、责任免除及赔付比例以电子保险条款为准；"
            "投保前请如实完成健康告知并确认被保人信息。"
        ),
        plans=tuple(
            _plan(version_key, code)
            for code in plan_codes
        ),
    )


def _plan_name(code: str) -> str:
    return {
        "BASIC": "基础计划",
        "STANDARD": "标准计划",
        "ENHANCED": "升级计划",
        "SENIOR_STANDARD": "银龄标准计划",
        "INDIVIDUAL": "个人计划",
        "FAMILY": "家庭计划",
    }[code]


def _plan(version_key: str, code: str) -> Plan:
    config = _plan_config(code)
    return Plan(
        id=stable_id(f"plan:{version_key}:{code}"),
        code=code,
        name=_plan_name(code),
        summary=config.summary,
        premium_cents=config.premium_cents,
        coverage_amount_cents=config.coverage_amount_cents,
        min_age=config.min_age,
        max_age=config.max_age,
    )


def _plan_config(code: str) -> PlanConfig:
    return {
        "BASIC": PlanConfig(
            "覆盖住院医疗及约定门诊费用，适合首次配置医疗保障的人群。",
            23900,
            200_000_000,
            0,
            65,
        ),
        "STANDARD": PlanConfig(
            "提升医疗保障额度，兼顾常见疾病住院和重大疾病医疗支出。",
            39900,
            300_000_000,
            0,
            65,
        ),
        "ENHANCED": PlanConfig(
            "提供更高医疗额度和扩展责任，适合重视全面保障的家庭。",
            59900,
            600_000_000,
            0,
            65,
        ),
        "SENIOR_STANDARD": PlanConfig(
            "面向中老年人群的住院医疗计划，覆盖高发疾病住院费用。",
            19900,
            100_000_000,
            50,
            75,
        ),
        "INDIVIDUAL": PlanConfig(
            "覆盖个人日常意外身故、伤残及意外医疗责任。",
            9900,
            50_000_000,
            0,
            70,
        ),
        "FAMILY": PlanConfig(
            "一份计划覆盖家庭成员的常见意外风险，适合家庭统一配置。",
            15900,
            100_000_000,
            0,
            70,
        ),
    }[code]


def _admin(
    username: str,
    display_name: str,
    role: str,
    data_scope: str,
    permissions: tuple[str, ...],
    password_hash: str,
) -> AdminUser:
    return AdminUser(
        id=stable_id(f"admin:{username}"),
        username=username,
        password_hash=password_hash,
        display_name=display_name,
        status="ACTIVE",
        roles=(role,),
        permissions=permissions,
        data_scope=data_scope,
    )


if __name__ == "__main__":
    seeded = run_seed()
    print(
        f"已写入 {len(seeded.admin_users)} 个后台账号、"
        f"{len(seeded.products)} 个产品、{len(seeded.versions)} 个产品版本、"
        f"{len(seeded.promotion_codes)} 个推广码。"
    )
