"""运费计算插件（企业级升级版）

优先使用数据库中配置的运费方案（ShippingMethod）进行计算；
若数据库中没有配置任何激活方案，则降级为平铺费率：满99免运费，否则$10。

context 必须包含：
  subtotal        (Decimal) 商品小计
  shipping_method_id (int, optional) 前台选择的运费方案 ID
  shipping_address   (dict, optional) 含 country / province
  items              (list, optional) 含 quantity / weight_kg
"""
import asyncio
from decimal import Decimal
from fastapi import FastAPI
from app.core.signals import calculate_shipping

PLUGIN_META = {
    "name":         "shipping_flat_rate",
    "display_name": "运费计算引擎",
    "description":  "企业级运费计算，支持按地区、重量、金额的阶梯运费方案，包含免运费阈值与多承运商配置。",
    "icon":         "🚛",
    "category":     "物流",
    "version":      "1.0.0",
    "author":       "LS",
    "config_fields": [],
}


def init_plugin(app: FastAPI) -> None:
    @calculate_shipping.connect
    def on_calculate_shipping(sender, context, **kwargs) -> None:
        subtotal: Decimal = context.get("subtotal", Decimal("0"))
        method_id: int | None = context.get("shipping_method_id")
        address: dict = context.get("shipping_address") or {}
        items: list = context.get("items") or []

        # 如果上游已写入 shipping_total，不覆盖
        if "shipping_total" in context:
            return

        db = context.get("db")
        tenant_id = context.get("tenant_id")

        # ── 检查插件是否启用 ──────────────────────────────────────────
        if db and tenant_id:
            try:
                from app.core.services.plugin_helper import is_plugin_active
                loop = asyncio.get_event_loop()
                if loop.is_running():
                    fut = asyncio.run_coroutine_threadsafe(
                        is_plugin_active("shipping_flat_rate", db, tenant_id), loop
                    )
                    plugin_on = fut.result(timeout=3)
                else:
                    plugin_on = loop.run_until_complete(
                        is_plugin_active("shipping_flat_rate", db, tenant_id)
                    )
                if not plugin_on:
                    return  # 插件已停用，不写入 shipping_total
            except Exception:
                pass  # 检查失败时降级继续运行

        # ── 尝试企业级计算（需要数据库会话）──────────────────────────
        if db and tenant_id and method_id:
            from app.core.services.shipping_calculator import ShippingCalculator

            country = address.get("country", "NZ")
            province = address.get("province", "")
            total_weight = sum(
                Decimal(str(item.get("weight_kg", 0))) * item.get("quantity", 1)
                for item in items
            )
            total_items = sum(item.get("quantity", 1) for item in items)

            try:
                calc = ShippingCalculator(db, tenant_id)
                loop = asyncio.get_event_loop()
                if loop.is_running():
                    future = asyncio.run_coroutine_threadsafe(
                        calc.calculate_for_order(
                            method_id=method_id,
                            country=country,
                            province=province,
                            subtotal=subtotal,
                            total_weight_kg=total_weight,
                            total_items=total_items,
                        ),
                        loop,
                    )
                    context["shipping_total"] = future.result(timeout=5)
                else:
                    context["shipping_total"] = loop.run_until_complete(
                        calc.calculate_for_order(
                            method_id=method_id,
                            country=country,
                            province=province,
                            subtotal=subtotal,
                            total_weight_kg=total_weight,
                            total_items=total_items,
                        )
                    )
                return
            except Exception:
                pass  # 降级到简单平铺逻辑

        # 降级：简单平铺费率
        if subtotal >= Decimal("99"):
            context["shipping_total"] = Decimal("0")
        else:
            context["shipping_total"] = Decimal("10")
