#!/usr/bin/env python3
"""Seed Commercial Runtime registries from docs/reference catalogs (idempotent)."""
from __future__ import annotations

import asyncio
import sys
from pathlib import Path

import yaml
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine

# Allow running from the repo checkout or from the mounted /app directory in Docker.
SCRIPT_PATH = Path(__file__).resolve()
CORE_SERVICE_ROOT = SCRIPT_PATH.parents[1]
ROOT = next((parent for parent in SCRIPT_PATH.parents if (parent / "docs").exists()), CORE_SERVICE_ROOT)
sys.path.insert(0, str(CORE_SERVICE_ROOT))

from app.commercial.kinds import BUILTIN_REGISTRY_KINDS
from app.commercial.service import CommercialRegistryService
from app.core.config import settings
from app.models.commercial import CommercialRegistryKind, CommercialRegistryObject


async def ensure_kinds(session: AsyncSession) -> None:
    svc = CommercialRegistryService(session)
    for i, spec in enumerate(BUILTIN_REGISTRY_KINDS):
        await svc.repo.upsert_kind(
            CommercialRegistryKind(
                kind=spec.kind,
                path=spec.path,
                display_name=spec.display_name,
                description=spec.description,
                code_field=spec.code_field,
                list_envelope=spec.list_envelope,
                public_read=spec.public_read,
                enabled=True,
                sort_order=i * 10,
            )
        )
    await session.commit()


async def upsert_object(
    session: AsyncSession,
    *,
    kind: str,
    code: str,
    display_name: str,
    payload: dict,
    description: str | None = None,
    version_code: str = "2026.07.1",
) -> bool:
    existing = (
        await session.execute(
            select(CommercialRegistryObject).where(
                CommercialRegistryObject.kind == kind,
                CommercialRegistryObject.stable_code == code,
                CommercialRegistryObject.version_code == version_code,
                CommercialRegistryObject.tenant_id.is_(None),
            )
        )
    ).scalar_one_or_none()
    if existing:
        existing.display_name = display_name
        existing.description = description
        existing.payload = payload
        existing.status = "published"
        existing.visibility = "public"
        existing.is_deleted = False
        await session.flush()
        return False
    from datetime import datetime, timezone
    import re
    import uuid

    slug = re.sub(r"[^a-z0-9]+", "-", code.lower()).strip("-")
    session.add(
        CommercialRegistryObject(
            id=uuid.uuid4(),
            kind=kind,
            slug=slug,
            stable_code=code,
            version_code=version_code,
            display_name=display_name,
            description=description,
            status="published",
            visibility="public",
            tenant_id=None,
            payload=payload,
            meta_data={},
            published_at=datetime.now(timezone.utc),
        )
    )
    await session.flush()
    return True


async def seed(session: AsyncSession) -> dict[str, int]:
    await ensure_kinds(session)
    counts = {"kinds": len(BUILTIN_REGISTRY_KINDS), "created": 0}

    catalog_path = ROOT / "docs" / "reference" / "business-bundles.catalog.yaml"
    data = yaml.safe_load(catalog_path.read_text(encoding="utf-8")) if catalog_path.exists() else {}
    bundles = data.get("bundles") or []

    # Products derived from services referenced by bundles (open-ended)
    products = {
        "hospitality": ("Torbat Food", "/hospitality", "hospitality"),
        "payment": ("Torbat Pay", "/payment/hub", "payment"),
        "experience": ("Torbat Pages", "/experience/hub", "experience"),
        "delivery": ("Torbat Driver", "/delivery/hub", "delivery"),
        "loyalty": ("Torbat Loyalty", "/loyalty/hub", "loyalty"),
        "communication": ("Torbat Communication", "/communication", "communication"),
        "accounting": ("Torbat Accounting", "/accounting", "accounting"),
        "crm": ("Torbat CRM", "/crm/hub", "crm"),
        "sports_center": ("Torbat Sports", "/sports", "sports_center"),
        "identity-access": ("Torbat Identity", "/dashboard", "identity"),
    }
    for code, (name, route, service_key) in products.items():
        if await upsert_object(
            session,
            kind="products",
            code=code,
            display_name=name,
            description=f"Platform product {name}",
            payload={
                "product_code": code,
                "default_route": route,
                "service_key": service_key,
                "category": "platform",
                "trial_eligible": True,
                "visibility": "public",
            },
        ):
            counts["created"] += 1

    for b in bundles:
        code = b["bundle_code"]
        services = b.get("services") or []
        product_codes = [s["service_identifier"] for s in services if s.get("required")]
        product_codes += [
            s["service_identifier"]
            for s in services
            if not s.get("required") and s["service_identifier"] not in product_codes
        ]
        product_codes = [p.replace("sports-center", "sports_center").replace("identity-access", "identity-access") for p in product_codes]
        # Map identity-access product code used in products dict
        product_codes = [("identity-access" if p == "identity-access" else p) for p in product_codes]
        pricing_refs = [p.get("pricing_item_code") for p in (b.get("pricing_refs") or []) if isinstance(p, dict)]
        capability_codes: list[str] = []
        if "hospitality" in product_codes:
            capability_codes = [
                "hospitality.digital_menu",
                "hospitality.pos_lite",
                "hospitality.kitchen",
                "hospitality.reservation",
                "hospitality.analytics",
            ]
        if await upsert_object(
            session,
            kind="bundles",
            code=code,
            display_name=b.get("display_name") or code,
            version_code=str(b.get("version_code") or "2026.07.1"),
            payload={
                "bundle_code": code,
                "business_types": b.get("business_types") or [],
                "product_codes": product_codes,
                "capability_codes": capability_codes,
                "pricing_refs": [{"pricing_item_code": p} for p in pricing_refs],
                "services": services,
                "visibility": b.get("visibility") or {},
                "lifecycle": b.get("lifecycle") or {},
                "trial_eligible": True,
            },
        ):
            counts["created"] += 1

        for pref in b.get("pricing_refs") or []:
            pcode = pref.get("pricing_item_code") if isinstance(pref, dict) else None
            if not pcode:
                continue
            interval = "yearly" if "yearly" in pcode else "monthly"
            if await upsert_object(
                session,
                kind="pricing",
                code=pcode,
                display_name=pcode,
                payload={
                    "pricing_item_code": pcode,
                    "pricing_model": "subscription",
                    "interval": interval,
                    "currency": "IRR",
                    "amount_minor": None,
                    "bundle_code": code,
                    "trial_eligible": True,
                    "trial_days": 14,
                },
            ):
                counts["created"] += 1
            # Mirror pricing as plan shell for plan resolver
            plan_code = pcode.replace("price.", "plan.", 1) if pcode.startswith("price.") else f"plan.{pcode}"
            if await upsert_object(
                session,
                kind="plans",
                code=plan_code,
                display_name=plan_code,
                payload={
                    "plan_code": plan_code,
                    "pricing_item_code": pcode,
                    "bundle_code": code,
                    "trial_eligible": True,
                    "trial_days": 14,
                    "interval": interval,
                    "currency": "IRR",
                    "limits": {},
                    "renewal": {"interval": interval},
                },
            ):
                counts["created"] += 1

    business_types = [
        ("restaurant", "Restaurant", "رستوران", ["bundle.restaurant.starter"]),
        ("cafe", "Cafe", "کافه", ["bundle.cafe.starter"]),
        ("clinic", "Clinic", "کلینیک", ["bundle.clinic.starter"]),
        ("beauty_salon", "Beauty Salon", "سالن زیبایی", ["bundle.beauty.starter"]),
        ("sports_center", "Sports Center", "مرکز ورزشی", ["bundle.sports.starter"]),
        ("retail_shop", "Retail Shop", "فروشگاه", ["bundle.retail.starter"]),
        ("corporate_company", "Corporate", "شرکت سازمانی", ["bundle.corporate.crm"]),
        ("freelancer", "Freelancer", "فریلنسر", ["bundle.freelancer.starter"]),
    ]
    for code, en, fa, rec in business_types:
        if await upsert_object(
            session,
            kind="business_types",
            code=code,
            display_name=fa,
            payload={
                "business_type_code": code,
                "display_name": en,
                "display_name_fa": fa,
                "recommended_bundle_codes": rec,
                "active": True,
            },
        ):
            counts["created"] += 1

    # Recommendation rules
    rules = [
        (
            "r.restaurant.base",
            "Restaurant base",
            {"business_type_code": "restaurant"},
            {"bundle_code": "bundle.restaurant.starter", "score": 100, "reason": "نوع رستوران", "products": ["hospitality", "payment", "experience"]},
        ),
        (
            "r.cafe.base",
            "Cafe base",
            {"business_type_code": "cafe"},
            {"bundle_code": "bundle.cafe.starter", "score": 100, "reason": "نوع کافه", "products": ["hospitality", "payment"]},
        ),
        (
            "r.delivery.need",
            "Delivery need",
            {"delivery": True},
            {"score": 80, "reason": "نیاز به پیک", "services": ["delivery"], "products": ["delivery"]},
        ),
        (
            "r.crm.need",
            "CRM need",
            {"crm": True},
            {"score": 80, "reason": "نیاز به CRM", "services": ["crm"], "products": ["crm"]},
        ),
    ]
    for code, name, match, emit in rules:
        if await upsert_object(
            session,
            kind="recommendation_rules",
            code=code,
            display_name=name,
            payload={"rule_id": code, "priority": 100, "active": True, "match": match, "emit": emit},
        ):
            counts["created"] += 1

    # Assessment schema
    if await upsert_object(
        session,
        kind="assessment_schemas",
        code="default.business.assessment",
        display_name="ارزیابی کسب‌وکار",
        payload={
            "questions": [
                {
                    "question_id": "business_type_code",
                    "type": "select",
                    "label": "نوع کسب‌وکار",
                    "required": True,
                    "options_source": "business_types",
                },
                {
                    "question_id": "company_size",
                    "type": "select",
                    "label": "اندازه",
                    "required": True,
                    "options": [
                        {"value": "solo", "label": "تک‌نفره"},
                        {"value": "small", "label": "کوچک"},
                        {"value": "medium", "label": "متوسط"},
                        {"value": "large", "label": "بزرگ"},
                        {"value": "enterprise", "label": "سازمانی"},
                    ],
                },
                {
                    "question_id": "delivery",
                    "type": "boolean",
                    "label": "نیاز به پیک؟",
                    "required": False,
                },
                {
                    "question_id": "crm",
                    "type": "boolean",
                    "label": "نیاز به CRM؟",
                    "required": False,
                },
            ]
        },
    ):
        counts["created"] += 1

    # Capabilities sample (open-ended)
    for cap in ["digital_menu", "pos_lite", "kitchen", "reservation", "analytics"]:
        if await upsert_object(
            session,
            kind="capabilities",
            code=f"hospitality.{cap}",
            display_name=cap,
            payload={"capability_code": f"hospitality.{cap}", "service_key": "hospitality"},
        ):
            counts["created"] += 1

    # Domain policy
    if await upsert_object(
        session,
        kind="policies",
        code="domain.custom",
        display_name="Custom domain policy",
        payload={
            "custom_domain_allowed": True,
            "subdomain_only": False,
            "target": "domain",
            "reason": "طبق سیاست دامنه تجاری",
            "dns_instructions": ["CNAME → edge.torbatyar.ir"],
            "ssl_ready": True,
        },
    ):
        counts["created"] += 1

    # Notification templates (email / sms / push / in_app)
    for channel, code, subject in [
        ("email", "notify.welcome.email", "خوش آمدید"),
        ("sms", "notify.welcome.sms", "خوش آمدید"),
        ("push", "notify.trial.expiring.push", "پایان trial"),
        ("in_app", "notify.activation.in_app", "فعال‌سازی"),
    ]:
        if await upsert_object(
            session,
            kind="notifications",
            code=code,
            display_name=subject,
            payload={
                "notification_code": code,
                "channel": channel,
                "subject": subject,
                "body_template": "{{tenant_name}} — {{message}}",
                "locale": "fa-IR",
                "provider": "platform",
            },
        ):
            counts["created"] += 1

    if await upsert_object(
        session,
        kind="currencies",
        code="IRR",
        display_name="ریال ایران",
        payload={"currency_code": "IRR", "symbol": "﷼", "decimals": 0},
    ):
        counts["created"] += 1

    if await upsert_object(
        session,
        kind="regions",
        code="IR",
        display_name="ایران",
        payload={"region_code": "IR", "country_code": "IR"},
    ):
        counts["created"] += 1

    await session.commit()
    return counts


async def main() -> None:
    engine = create_async_engine(settings.database_url, future=True)
    Session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
    async with Session() as session:
        counts = await seed(session)
        print(f"commercial seed complete: {counts}")
    await engine.dispose()


if __name__ == "__main__":
    asyncio.run(main())
