"""Background catalog provision jobs (avoids HTTP/proxy timeouts on long Magento/Shopify writes)."""

from __future__ import annotations

import logging
import threading
import uuid
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

from db.channel_catalog_provision import ProvisionOptions, provision_channel_catalogs
from db.models import MagentoConnection, ShopifyConnection
from db.session import get_session

logger = logging.getLogger(__name__)

_jobs_lock = threading.Lock()
_jobs: Dict[str, Dict[str, Any]] = {}


def _utcnow() -> datetime:
    return datetime.now(timezone.utc)


def _set_job(job_id: str, **updates: Any) -> None:
    with _jobs_lock:
        row = _jobs.setdefault(job_id, {})
        row.update(updates)


def get_catalog_provision_job(job_id: str) -> Optional[Dict[str, Any]]:
    with _jobs_lock:
        row = _jobs.get(job_id)
        return dict(row) if row else None


def start_catalog_provision_job(params: Dict[str, Any]) -> str:
    job_id = str(uuid.uuid4())
    _set_job(
        job_id,
        id=job_id,
        status="queued",
        created_at=_utcnow().isoformat(),
        params=dict(params),
        result=None,
        error=None,
    )
    thread = threading.Thread(
        target=_run_catalog_provision_job,
        args=(job_id, dict(params)),
        name=f"catalog-provision-{job_id[:8]}",
        daemon=True,
    )
    thread.start()
    return job_id


def _list_param(value: Any) -> List[str]:
    if value is None:
        return []
    if isinstance(value, str):
        return [part.strip() for part in value.split(",") if part.strip()]
    if isinstance(value, (list, tuple, set)):
        return [str(part).strip() for part in value if str(part).strip()]
    return [str(value).strip()] if str(value).strip() else []


def _run_catalog_provision_job(job_id: str, params: Dict[str, Any]) -> None:
    _set_job(job_id, status="running", started_at=_utcnow().isoformat())
    try:
        result = _execute_catalog_provision(params)
        _set_job(
            job_id,
            status="completed",
            finished_at=_utcnow().isoformat(),
            result=result,
        )
    except Exception as exc:
        logger.exception("catalog provision job %s failed", job_id)
        _set_job(
            job_id,
            status="failed",
            finished_at=_utcnow().isoformat(),
            error=str(exc),
        )


def _execute_catalog_provision(params: Dict[str, Any]) -> Dict[str, Any]:
    from main import _default_native_connection_id, _resolve_native_connection_id

    magento_connection_id = params.get("magento_connection_id")
    shopify_connection_id = params.get("shopify_connection_id")
    only_assigned = bool(params.get("only_assigned", True))
    dry_run = bool(params.get("dry_run", True))
    include_magento = bool(params.get("include_magento", True))
    include_shopify = bool(params.get("include_shopify", True))
    create_missing = bool(params.get("create_missing", True))
    assign_skus = bool(params.get("assign_skus", True))
    delta_only = bool(params.get("delta_only", True))
    seed_master_listing_paths = bool(params.get("seed_master_listing_paths", True))
    provision_attributes = bool(params.get("provision_attributes", True))
    include_brand_collections = bool(params.get("include_brand_collections", True))
    baseline_first = bool(params.get("baseline_first", False))
    shopify_brand_filter = _list_param(
        params.get("shopify_brand_filter")
        if "shopify_brand_filter" in params
        else params.get("shopify_brands")
    )
    limit = params.get("limit")

    with get_session() as session:
        native_magento_id = (
            _resolve_native_connection_id(session, magento_connection_id)
            if magento_connection_id
            else _default_native_connection_id(session, "magento")
        )
        native_shopify_id = (
            _resolve_native_connection_id(session, shopify_connection_id)
            if shopify_connection_id
            else _default_native_connection_id(session, "shopify")
        )

        baseline_result = None
        if baseline_first and include_magento and not dry_run and native_magento_id is not None:
            from app.jobs.magento_baseline_sync import run_baseline_sync

            logger.info(
                "Running Magento baseline sync before catalog provision (connection=%s)",
                native_magento_id,
            )
            baseline_result = run_baseline_sync(
                int(native_magento_id),
                force=True,
                session=session,
            )
            if baseline_result.get("status") == "failed":
                raise RuntimeError(
                    f"Baseline sync failed: {baseline_result.get('error') or baseline_result}"
                )

        magento_api = None
        if include_magento and not dry_run and create_missing:
            if native_magento_id is None:
                raise RuntimeError("No Magento connection available")
            magento_connection = session.get(MagentoConnection, native_magento_id)
            if magento_connection is None:
                raise RuntimeError("Magento connection not found")
            if magento_connection.status != "active":
                raise RuntimeError("Magento connection is disabled")
            from magento.oauth_client import MagentoOAuthClient, build_magento_oauth_kwargs
            from magento.magento_api import MagentoRestClient

            oauth = MagentoOAuthClient(**build_magento_oauth_kwargs(magento_connection))
            magento_api = MagentoRestClient(oauth)

        shopify_client = None
        shopify_shop_code = None
        if include_shopify and not dry_run and create_missing:
            if native_shopify_id is None:
                raise RuntimeError("No Shopify connection available")
            shopify_connection = session.get(ShopifyConnection, native_shopify_id)
            if shopify_connection is None:
                raise RuntimeError("Shopify connection not found")
            if shopify_connection.status != "active":
                raise RuntimeError("Shopify connection is disabled")
            from shopify.connections import build_client

            shopify_client = build_client(shopify_connection)
            shopify_shop_code = shopify_connection.shop_code

        result = provision_channel_catalogs(
            session,
            options=ProvisionOptions(
                magento_connection_id=native_magento_id if include_magento else None,
                shopify_connection_id=native_shopify_id if include_shopify else None,
                only_assigned=only_assigned,
                dry_run=dry_run,
                include_magento=include_magento,
                include_shopify=include_shopify,
                create_missing=create_missing,
                assign_skus=assign_skus,
                delta_only=delta_only,
                seed_master_listing_paths=seed_master_listing_paths,
                provision_attributes=provision_attributes,
                include_brand_collections=include_brand_collections,
                shopify_brand_filter=shopify_brand_filter,
                limit=limit,
            ),
            magento_api=magento_api,
            shopify_client=shopify_client,
            shopify_shop_code=shopify_shop_code,
        )
        if not dry_run:
            session.commit()
        if baseline_result is not None:
            result = dict(result)
            result["baseline"] = baseline_result
        return result
