from decimal import Decimal
from datetime import datetime
from sqlalchemy import BigInteger, String, JSON, DECIMAL, Integer, UniqueConstraint, Index, ForeignKey
from sqlalchemy.dialects.mysql import TINYINT, DATETIME as MYSQL_DATETIME
from sqlalchemy.orm import Mapped, mapped_column
from app.core.models.base import Base, TimestampMixin, TenantMixin


class Discount(Base, TenantMixin, TimestampMixin):
    """促销 / 优惠券规则

    rule_type 取值：
        order_amount_off     满减（支持阶梯，见 discount_tiers）
        order_percent_off    满折（支持阶梯）
        product_amount_off   指定商品直减 / 折扣
        product_buyxgety     买 X 件 A 赠 Y 件 B（含同款 BOGO）
        category_percent_off 指定分类打折
        free_shipping        免运费
        points_multiplier    积分倍数活动

    向后兼容别名（旧数据）：
        percentage  → order_percent_off
        fixed       → order_amount_off
        buy_x_get_y → product_buyxgety
    """

    __tablename__ = "discounts"
    __table_args__ = (
        UniqueConstraint("tenant_id", "code", name="uk_discount_tenant_code"),
        Index("ix_discount_start", "start_at"),
        Index("ix_discount_end", "end_at"),
        Index("ix_discount_active", "is_active"),
        Index("ix_discount_priority", "priority"),
        {
            "mysql_engine": "InnoDB",
            "mysql_charset": "utf8mb4",
            "mysql_collate": "utf8mb4_unicode_ci",
        },
    )

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)

    # ── 基础信息 ───────────────────────────────────────────────
    name: Mapped[str] = mapped_column(String(100), nullable=False, default="", comment="促销展示名称")
    code: Mapped[str | None] = mapped_column(String(50), nullable=True, comment="优惠码，NULL = 自动应用")
    type: Mapped[str] = mapped_column(String(30), nullable=False, comment="rule_type，见类注释")
    value: Mapped[Decimal] = mapped_column(DECIMAL(10, 2), nullable=False, default=0, comment="折扣值（百分比或固定金额）")

    # ── 触发条件 ───────────────────────────────────────────────
    min_order_amount: Mapped[Decimal | None] = mapped_column(DECIMAL(12, 2), nullable=True, comment="最低订单金额")
    condition_min_qty: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="触发所需最少商品件数")
    condition_order_count_min: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="客户历史订单数下限（含），0 = 首单")
    condition_order_count_max: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="客户历史订单数上限（含），NULL = 不限")
    condition_customer_level_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, comment="要求达到的会员等级 ID")
    condition_product_ids: Mapped[list | None] = mapped_column(JSON, nullable=True, comment="触发条件商品 ID 列表")
    condition_category_ids: Mapped[list | None] = mapped_column(JSON, nullable=True, comment="触发条件分类 ID 列表")

    # ── 折扣目标 ───────────────────────────────────────────────
    discount_product_ids: Mapped[list | None] = mapped_column(JSON, nullable=True, comment="享受折扣的商品 ID 列表（NULL = 同 condition）")
    discount_category_ids: Mapped[list | None] = mapped_column(JSON, nullable=True, comment="享受折扣的分类 ID 列表（NULL = 同 condition）")
    discount_qty: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="BOGO：赠品件数")
    discount_qualifier: Mapped[str | None] = mapped_column(String(10), nullable=True, comment="least=最便宜优先 / most=最贵优先")

    # ── 执行控制 ───────────────────────────────────────────────
    priority: Mapped[int] = mapped_column(Integer, nullable=False, default=0, comment="执行优先级，数值越大越先执行")
    stop: Mapped[int] = mapped_column(TINYINT(1), nullable=False, default=0, comment="命中后停止执行后续促销")
    apply_once: Mapped[int] = mapped_column(TINYINT(1), nullable=False, default=1, comment="每单仅享一次（0=按匹配组数倍增）")
    is_stackable: Mapped[int] = mapped_column(TINYINT(1), nullable=False, default=1, comment="可与其他促销叠加")

    # ── 积分活动 ───────────────────────────────────────────────
    points_multiplier: Mapped[Decimal | None] = mapped_column(DECIMAL(4, 2), nullable=True, comment="积分倍数，如 2.00 = 双倍积分")

    # ── 使用限制 ───────────────────────────────────────────────
    usage_limit: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="总使用次数上限，NULL = 无限")
    usage_limit_per_customer: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="每人最多使用次数，NULL = 不限")
    used_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, comment="已使用总次数")

    # ── 有效期 ────────────────────────────────────────────────
    start_at: Mapped[datetime | None] = mapped_column(MYSQL_DATETIME(fsp=3), nullable=True, comment="生效时间")
    end_at: Mapped[datetime | None] = mapped_column(MYSQL_DATETIME(fsp=3), nullable=True, comment="失效时间")
    is_active: Mapped[int] = mapped_column(TINYINT(1), nullable=False, default=1)

    # ── 兼容扩展 ──────────────────────────────────────────────
    extra_rules: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="预留扩展字段")

    def is_valid(self, order_amount: Decimal) -> bool:
        """基础有效性检查（日期校验由 pricing/engine 层处理）"""
        if not self.is_active:
            return False
        if self.usage_limit is not None and self.used_count >= self.usage_limit:
            return False
        if self.min_order_amount is not None and order_amount < self.min_order_amount:
            return False
        return True

    @property
    def normalized_type(self) -> str:
        """将旧 type 值映射到新规则名称"""
        _alias = {
            "percentage": "order_percent_off",
            "fixed": "order_amount_off",
            "buy_x_get_y": "product_buyxgety",
        }
        return _alias.get(self.type, self.type)

    def __repr__(self) -> str:
        return f"<Discount id={self.id} code={self.code!r} type={self.type!r}>"
