"""
Canifa Persona Generator
=========================
Inspired by MiroFish OasisProfileGenerator — nhưng nhẹ hơn 90%.

MiroFish: Entity từ Knowledge Graph → 2000 chữ → mô phỏng MXH
Canifa:   LLM generate trực tiếp → 100-150 chữ → test chatbot

Model: gpt-5.4-nano (DEFAULT_MODEL)
"""

import json
import logging
import random
from dataclasses import dataclass
from typing import Any

from common.llm_factory import create_llm
from config import DEFAULT_MODEL

logger = logging.getLogger(__name__)

# Model — dùng gpt-5.4-nano từ env
SIM_MODEL = DEFAULT_MODEL


# ═══════════════════════════════════════════════════════════════
# DATA MODEL
# ═══════════════════════════════════════════════════════════════
@dataclass
class CanifaPersona:
    """Canifa customer persona — lightweight version of MiroFish OasisAgentProfile."""

    # Identity
    name: str
    age: int
    gender: str          # "male" | "female"
    job: str
    income_range: str    # "5-10tr" | "10-20tr"
    mbti: str

    # Shopping context
    shopping_for: str    # "Bản thân" | "Con gái 3 tuổi"
    budget: str          # "200k-500k"
    occasion: str        # "Đi làm" | "Đi chơi"
    style_preference: str

    # Chat behavior
    chat_style: str      # Mô tả cách chat
    system_prompt: str   # Prompt để LLM đóng vai

    # Conversion criteria
    conversion_trigger: str   # Điều kiện MUA
    drop_trigger: str         # Điều kiện BỎ

    # Metadata
    persona_id: int = 0
    archetype: str = ""

    def to_dict(self) -> dict[str, Any]:
        return {
            "persona_id": self.persona_id,
            "name": self.name,
            "age": self.age,
            "gender": self.gender,
            "job": self.job,
            "income_range": self.income_range,
            "mbti": self.mbti,
            "archetype": self.archetype,
            "shopping_for": self.shopping_for,
            "budget": self.budget,
            "occasion": self.occasion,
            "style_preference": self.style_preference,
            "chat_style": self.chat_style,
            "system_prompt": self.system_prompt,
            "conversion_trigger": self.conversion_trigger,
            "drop_trigger": self.drop_trigger,
        }


# ═══════════════════════════════════════════════════════════════
# ARCHETYPES — Khách hàng Canifa điển hình
# ═══════════════════════════════════════════════════════════════
CANIFA_ARCHETYPES = [
    "Mẹ bỉm sữa — mua đồ cho con nhỏ, cẩn thận, so sánh giá",
    "GenZ TikToker — thích trend, chat nhanh, dùng slang/emoji",
    "Nhân viên văn phòng nữ — mua đồ đi làm, thanh lịch, budget vừa",
    "Ông chú IT — mua quà cho vợ/con gái, không rành thời trang",
    "Sinh viên tiết kiệm — budget thấp, săn sale, hỏi nhiều",
    "Chị em công sở — mua theo nhóm, hay hỏi ý kiến, thích combo",
    "Anh trai gym — tìm đồ thể thao/polo, quan tâm chất liệu",
    "Bà ngoại — mua cho cháu, không quen chat, hỏi đơn giản",
    "Fashionista — biết nhiều brand, kén chọn, so sánh Canifa vs Uniqlo",
    "Khách vãng lai — vào hỏi 1 câu rồi đi, test bot giữ chân",
]


# ═══════════════════════════════════════════════════════════════
# PROMPTS
# ═══════════════════════════════════════════════════════════════
_GENERATE_SYSTEM = """Bạn là chuyên gia tạo persona khách hàng cho thương hiệu thời trang CANIFA Việt Nam.
Tạo persona CHÂN THỰC, NGẮN GỌN dùng cho test chatbot bán hàng.
Trả về JSON array. KHÔNG giải thích."""


def _build_generate_prompt(count: int, archetypes: list[str] | None = None) -> str:
    if not archetypes:
        archetypes = random.sample(CANIFA_ARCHETYPES, min(count, len(CANIFA_ARCHETYPES)))

    archetypes_str = "\n".join(f"  {i+1}. {a}" for i, a in enumerate(archetypes))

    return f"""Tạo {count} persona khách hàng CANIFA:
{archetypes_str}

Mỗi persona là 1 JSON object:
- "name": Tên Việt Nam (VD: "Chị Lan", "Bé Vy")
- "age": Số tuổi (18-65)
- "gender": "male" hoặc "female"
- "job": Nghề nghiệp
- "income_range": Thu nhập/tháng (VD: "8-12tr")
- "mbti": MBTI type
- "archetype": Tên nhóm khách
- "shopping_for": Mua cho ai
- "budget": Ngân sách lần này (VD: "300k-600k")
- "occasion": Dịp mua
- "style_preference": Phong cách thích
- "chat_style": Cách chat 1-2 câu
- "conversion_trigger": Điều kiện MUA
- "drop_trigger": Điều kiện BỎ ĐI

Trả JSON array [{count} objects]. Đa dạng tuổi, giới tính, thu nhập."""


def _build_roleplay_prompt(p: dict) -> str:
    """Build system prompt để LLM đóng vai persona."""
    return f"""Bạn đóng vai khách hàng tên {p['name']}, {p['age']} tuổi, {p['job']}.

PERSONA:
- Giới tính: {"Nữ" if p['gender'] == 'female' else "Nam"}
- Thu nhập: {p['income_range']}/tháng | MBTI: {p['mbti']}
- Nhóm: {p['archetype']}

MUA SẮM:
- Mua cho: {p['shopping_for']} | Budget: {p['budget']}
- Dịp: {p['occasion']} | Style: {p['style_preference']}

CÁCH CHAT: {p['chat_style']}

QUY TẮC:
1. Chat ĐÚNG tính cách, budget, mục đích
2. SP phù hợp → hứng thú, hỏi thêm
3. SP không hợp → từ chối nhẹ hoặc hỏi cái khác
4. MUA khi: {p['conversion_trigger']}
5. BỎ khi: {p['drop_trigger']}
6. Chat tự nhiên, ngắn. KHÔNG nói "tôi là AI"."""


# ═══════════════════════════════════════════════════════════════
# GENERATOR
# ═══════════════════════════════════════════════════════════════
async def generate_personas(
    count: int = 5,
    archetypes: list[str] | None = None,
    model_name: str | None = None,
) -> list[CanifaPersona]:
    """
    Generate N personas bằng LLM.
    Retry pattern lấy từ MiroFish (max 3, giảm temperature).
    """
    count = max(1, min(count, 20))
    model = model_name or SIM_MODEL

    logger.info(f"🎭 Generating {count} personas | model={model}")
    llm = create_llm(model, streaming=False, json_mode=True)
    prompt = _build_generate_prompt(count, archetypes)

    # Retry (MiroFish pattern)
    for attempt in range(3):
        try:
            response = await llm.ainvoke([
                {"role": "system", "content": _GENERATE_SYSTEM},
                {"role": "user", "content": prompt},
            ])

            raw = response.content
            if isinstance(raw, list):
                raw = "".join(str(c.get("text", c) if isinstance(c, dict) else c) for c in raw)

            data = json.loads(raw)

            # Handle wrapped response
            if isinstance(data, dict):
                for key in ("personas", "data", "results", "items"):
                    if key in data and isinstance(data[key], list):
                        data = data[key]
                        break
                else:
                    data = [data]

            # Convert to CanifaPersona
            personas = []
            for i, p in enumerate(data[:count]):
                try:
                    persona = CanifaPersona(
                        persona_id=i + 1,
                        name=p.get("name", f"Persona_{i+1}"),
                        age=int(p.get("age", 25)),
                        gender=p.get("gender", "female"),
                        job=p.get("job", "Không rõ"),
                        income_range=p.get("income_range", "10-15tr"),
                        mbti=p.get("mbti", "ISFJ"),
                        archetype=p.get("archetype", "Khách vãng lai"),
                        shopping_for=p.get("shopping_for", "Bản thân"),
                        budget=p.get("budget", "300k-700k"),
                        occasion=p.get("occasion", "Đi chơi"),
                        style_preference=p.get("style_preference", "Basic"),
                        chat_style=p.get("chat_style", "Chat bình thường"),
                        system_prompt=_build_roleplay_prompt(p),
                        conversion_trigger=p.get("conversion_trigger", "SP phù hợp"),
                        drop_trigger=p.get("drop_trigger", "Không tìm được SP"),
                    )
                    personas.append(persona)
                except Exception as e:
                    logger.warning(f"⚠️ Skip persona {i}: {e}")

            logger.info(f"✅ Generated {len(personas)} personas")
            return personas

        except json.JSONDecodeError as e:
            logger.warning(f"⚠️ JSON fail (attempt {attempt+1}/3): {e}")
        except Exception as e:
            logger.warning(f"⚠️ Generate fail (attempt {attempt+1}/3): {e}")

    raise RuntimeError("Failed to generate personas after 3 attempts")
