"""Account-level creative material source strategy.

The default remains historical recall. AI generation and external recall are
enabled only for accounts explicitly configured for those module B branches.
"""

from __future__ import annotations

import logging
from dataclasses import dataclass

logger = logging.getLogger(__name__)

MATERIAL_SOURCE_HISTORY = "history"
MATERIAL_SOURCE_AI_GENERATED = "ai_generated"
MATERIAL_SOURCE_EXTERNAL_RECALL = "external_recall"

_AI_SOURCE_VALUES = {
    "ai",
    "ai_generated",
    "ai生成",
    "ai生成素材",
    "生成素材",
    "新生成素材",
}
_HISTORY_SOURCE_VALUES = {
    "",
    "history",
    "历史",
    "历史素材",
    "历史投放素材",
    "历史已投素材",
}
_EXTERNAL_SOURCE_VALUES = {
    "external",
    "external_recall",
    "外部",
    "外部素材",
    "外部素材召回",
    "外部合作素材",
}
_TRUE_VALUES = {"1", "true", "yes", "y", "是", "允许", "回退"}


@dataclass(frozen=True)
class AccountMaterialStrategy:
    account_id: int
    material_source: str = MATERIAL_SOURCE_HISTORY
    ai_fallback_to_history: bool = False

    @property
    def use_ai_generated(self) -> bool:
        return self.material_source == MATERIAL_SOURCE_AI_GENERATED

    @property
    def use_external_recall(self) -> bool:
        return self.material_source == MATERIAL_SOURCE_EXTERNAL_RECALL


def normalize_material_source(raw: object) -> str:
    text = str(raw or "").strip().lower()
    if text in _AI_SOURCE_VALUES:
        return MATERIAL_SOURCE_AI_GENERATED
    if text in _HISTORY_SOURCE_VALUES:
        return MATERIAL_SOURCE_HISTORY
    if text in _EXTERNAL_SOURCE_VALUES:
        return MATERIAL_SOURCE_EXTERNAL_RECALL
    raise ValueError(f"未知素材来源:{raw}")


def parse_bool_flag(raw: object) -> bool:
    return str(raw or "").strip().lower() in _TRUE_VALUES


def ensure_account_material_strategy_columns() -> None:
    """Add strategy columns when deploying to an older DB schema."""
    from db.connection import get_connection

    conn = get_connection()
    try:
        with conn.cursor() as cur:
            cur.execute(
                """
                SELECT COLUMN_NAME
                FROM information_schema.COLUMNS
                WHERE TABLE_SCHEMA = DATABASE()
                  AND TABLE_NAME = 'ad_creation_account_config'
                  AND COLUMN_NAME IN ('material_source', 'ai_fallback_to_history')
                """
            )
            existing = {row["COLUMN_NAME"] for row in (cur.fetchall() or [])}
            if "material_source" not in existing:
                cur.execute(
                    """
                    ALTER TABLE ad_creation_account_config
                    ADD COLUMN material_source VARCHAR(50) NOT NULL DEFAULT 'history'
                    COMMENT '创意素材来源:history/ai_generated/external_recall'
                    AFTER feedback_key
                    """
                )
            if "ai_fallback_to_history" not in existing:
                cur.execute(
                    """
                    ALTER TABLE ad_creation_account_config
                    ADD COLUMN ai_fallback_to_history BOOLEAN NOT NULL DEFAULT FALSE
                    COMMENT 'AI生成失败时是否回退历史素材'
                    AFTER material_source
                    """
                )
        conn.commit()
    finally:
        conn.close()


def load_account_material_strategy(account_id: int) -> AccountMaterialStrategy:
    """Load configured material strategy. Missing config defaults to history."""
    from db.connection import get_connection

    try:
        ensure_account_material_strategy_columns()
    except Exception as e:
        logger.warning(
            "[material_strategy] ensure columns failed account=%d, fallback history: %s",
            account_id, e,
        )
        return AccountMaterialStrategy(account_id=account_id)

    conn = get_connection()
    try:
        with conn.cursor() as cur:
            cur.execute(
                """
                SELECT material_source, ai_fallback_to_history
                FROM ad_creation_account_config
                WHERE account_id=%s
                LIMIT 1
                """,
                (account_id,),
            )
            row = cur.fetchone() or {}
    finally:
        conn.close()

    try:
        source = normalize_material_source(row.get("material_source"))
    except ValueError:
        logger.warning(
            "[material_strategy] account=%d material_source=%r 非法,按 history 处理",
            account_id, row.get("material_source"),
        )
        source = MATERIAL_SOURCE_HISTORY
    return AccountMaterialStrategy(
        account_id=account_id,
        material_source=source,
        ai_fallback_to_history=bool(row.get("ai_fallback_to_history")),
    )
