"""
测试数据工厂
支持创建、批量生成、持久化测试数据
"""
import json
import uuid
import random
import string
from dataclasses import dataclass, field, asdict
from typing import Optional, List, Dict, Any, Type, TypeVar, Generic, Callable
from pathlib import Path
from datetime import datetime, timedelta
from abc import ABC, abstractmethod
from loguru import logger


T = TypeVar('T')


@dataclass
class FactoryConfig:
    """工厂配置"""
    persist_enabled: bool = False
    persist_file: str = "./test_data/created_data.json"
    sequence_start: int = 1
    random_seed: Optional[int] = None


@dataclass
class FakeUser:
    """测试用户数据"""
    id: str = ""
    username: str = ""
    email: str = ""
    password: str = ""
    first_name: str = ""
    last_name: str = ""
    phone: str = ""
    role: str = "user"
    is_active: bool = True
    created_at: str = ""


@dataclass
class FakeProduct:
    """测试产品数据"""
    id: str = ""
    name: str = ""
    description: str = ""
    price: float = 0.0
    category: str = ""
    stock: int = 0
    sku: str = ""
    image_url: str = ""
    is_available: bool = True


@dataclass
class FakeOrder:
    """测试订单数据"""
    id: str = ""
    order_number: str = ""
    user_id: str = ""
    products: List[Dict[str, Any]] = field(default_factory=list)
    total_amount: float = 0.0
    status: str = "pending"
    shipping_address: str = ""
    created_at: str = ""


class TestDataFactory(Generic[T], ABC):
    """
    测试数据工厂基类
    支持创建、批量生成、序列号、持久化
    """

    def __init__(self, config: Optional[FactoryConfig] = None):
        self.config = config or FactoryConfig()
        self._sequence = self.config.sequence_start
        self._created_data: List[Dict[str, Any]] = []

        if self.config.random_seed is not None:
            random.seed(self.config.random_seed)

    def create(self, overrides: Optional[Dict[str, Any]] = None) -> T:
        """
        创建单个测试数据

        Args:
            overrides: 覆盖的字段值

        Returns:
            T: 创建的数据对象
        """
        data = self._generate_data()
        if overrides:
            self._apply_overrides(data, overrides)

        # 应用后处理
        self._post_process(data)

        # 记录创建的数据
        self._created_data.append(self._to_dict(data))

        # 持久化
        if self.config.persist_enabled:
            self._save_to_file()

        return data

    def create_many(self, count: int, overrides: Optional[Dict[str, Any]] = None) -> List[T]:
        """
        批量创建测试数据

        Args:
            count: 创建数量
            overrides: 覆盖的字段值（应用到所有数据）

        Returns:
            List[T]: 创建的数据列表
        """
        results = []
        for _ in range(count):
            data = self.create(overrides)
            results.append(data)
        return results

    def create_with_sequence(self, field: str = "id") -> T:
        """
        创建带序列号的数据

        Args:
            field: 应用序列号的字段

        Returns:
            T: 创建的数据对象
        """
        data = self.create()
        if hasattr(data, field):
            setattr(data, field, f"{field}_{self._sequence}")
            self._sequence += 1
        return data

    def get_created_data(self) -> List[Dict[str, Any]]:
        """获取所有已创建的数据"""
        return self._created_data.copy()

    def clear_created_data(self):
        """清除已创建的数据记录"""
        self._created_data.clear()
        if self.config.persist_enabled:
            self._save_to_file()

    def enable_persistence(self, file_path: str):
        """启用持久化"""
        self.config.persist_enabled = True
        self.config.persist_file = file_path
        self._ensure_dir(file_path)

    # ==================== 抽象方法 ====================

    @abstractmethod
    def _generate_data(self) -> T:
        """生成基础数据"""
        pass

    @abstractmethod
    def _to_dict(self, data: T) -> Dict[str, Any]:
        """转换为字典"""
        pass

    # ==================== 私有方法 ====================

    def _apply_overrides(self, data: T, overrides: Dict[str, Any]):
        """应用覆盖值"""
        for key, value in overrides.items():
            if hasattr(data, key):
                setattr(data, key, value)

    def _post_process(self, data: T):
        """后处理（子类可覆盖）"""
        pass

    def _save_to_file(self):
        """保存到文件"""
        try:
            file_path = self.config.persist_file
            self._ensure_dir(file_path)

            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(self._created_data, f, ensure_ascii=False, indent=2)

        except Exception as e:
            logger.error(f"保存测试数据失败: {e}")

    def _ensure_dir(self, file_path: str):
        """确保目录存在"""
        dir_path = Path(file_path).parent
        dir_path.mkdir(parents=True, exist_ok=True)

    # ==================== 工具方法 ====================

    @staticmethod
    def generate_uuid() -> str:
        """生成 UUID"""
        return str(uuid.uuid4())

    @staticmethod
    def generate_random_string(length: int = 10) -> str:
        """生成随机字符串"""
        return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

    @staticmethod
    def generate_random_email(domain: str = "test.com") -> str:
        """生成随机邮箱"""
        username = TestDataFactory.generate_random_string(8).lower()
        return f"{username}@{domain}"

    @staticmethod
    def generate_random_phone() -> str:
        """生成随机电话号码"""
        return f"1{random.choice(['3', '5', '7', '8', '9'])}{''.join(random.choices(string.digits, k=9))}"

    @staticmethod
    def generate_random_date(start_year: int = 2020, end_year: int = 2025) -> str:
        """生成随机日期"""
        start = datetime(start_year, 1, 1)
        end = datetime(end_year, 12, 31)
        delta = end - start
        random_days = random.randint(0, delta.days)
        random_date = start + timedelta(days=random_days)
        return random_date.strftime("%Y-%m-%d")

    @staticmethod
    def random_choice(items: List[Any]) -> Any:
        """随机选择"""
        return random.choice(items)

    @staticmethod
    def random_int(min_val: int, max_val: int) -> int:
        """随机整数"""
        return random.randint(min_val, max_val)

    @staticmethod
    def random_float(min_val: float, max_val: float, decimals: int = 2) -> float:
        """随机浮点数"""
        return round(random.uniform(min_val, max_val), decimals)


# ==================== 具体工厂实现 ====================

class UserFactory(TestDataFactory[FakeUser]):
    """用户数据工厂"""

    ROLES = ["user", "admin", "moderator", "guest"]
    FIRST_NAMES = ["张", "李", "王", "刘", "陈", "杨", "黄", "赵", "周", "吴"]
    LAST_NAMES = ["伟", "芳", "娜", "敏", "静", "强", "磊", "洋", "勇", "艳"]

    def _generate_data(self) -> FakeUser:
        return FakeUser(
            id=self.generate_uuid(),
            username=f"user_{self.generate_random_string(6).lower()}",
            email=self.generate_random_email(),
            password=self.generate_random_string(12),
            first_name=self.random_choice(self.FIRST_NAMES),
            last_name=self.random_choice(self.LAST_NAMES),
            phone=self.generate_random_phone(),
            role=self.random_choice(self.ROLES),
            is_active=self.random_choice([True, True, True, False]),  # 75% 激活
            created_at=self.generate_random_date(),
        )

    def _to_dict(self, data: FakeUser) -> Dict[str, Any]:
        return asdict(data)

    def create_admin(self, overrides: Optional[Dict[str, Any]] = None) -> FakeUser:
        """创建管理员用户"""
        admin_overrides = {"role": "admin", **(overrides or {})}
        return self.create(admin_overrides)

    def create_test_user(self, overrides: Optional[Dict[str, Any]] = None) -> FakeUser:
        """创建测试用户"""
        test_overrides = {"role": "user", "is_active": True, **(overrides or {})}
        return self.create(test_overrides)

    def create_inactive_user(self, overrides: Optional[Dict[str, Any]] = None) -> FakeUser:
        """创建未激活用户"""
        inactive_overrides = {"is_active": False, **(overrides or {})}
        return self.create(inactive_overrides)


class ProductFactory(TestDataFactory[FakeProduct]):
    """产品数据工厂"""

    CATEGORIES = ["电子产品", "服装", "食品", "家居", "图书", "运动", "美妆", "玩具"]
    PRODUCT_NAMES = {
        "电子产品": ["智能手机", "笔记本电脑", "平板电脑", "耳机", "智能手表"],
        "服装": ["T恤", "牛仔裤", "连衣裙", "外套", "运动鞋"],
        "食品": ["巧克力", "饼干", "坚果", "咖啡", "茶叶"],
        "家居": ["沙发", "床", "书桌", "台灯", "收纳盒"],
        "图书": ["小说", "技术书籍", "杂志", "漫画", "教材"],
        "运动": ["篮球", "足球", "瑜伽垫", "哑铃", "跑步机"],
        "美妆": ["口红", "面膜", "精华液", "防晒霜", "香水"],
        "玩具": ["积木", "拼图", "遥控车", "毛绒玩具", "益智玩具"],
    }

    def _generate_data(self) -> FakeProduct:
        category = self.random_choice(self.CATEGORIES)
        product_name = self.random_choice(self.PRODUCT_NAMES.get(category, ["产品"]))

        return FakeProduct(
            id=self.generate_uuid(),
            name=product_name,
            description=f"这是一个{product_name}的详细描述，包含高品质材料和精美设计。",
            price=self.random_float(10.0, 9999.0),
            category=category,
            stock=self.random_int(0, 1000),
            sku=f"SKU-{self.generate_random_string(8).upper()}",
            image_url=f"https://example.com/images/{self.generate_random_string(10)}.jpg",
            is_available=self.random_choice([True, True, True, False]),
        )

    def _to_dict(self, data: FakeProduct) -> Dict[str, Any]:
        return asdict(data)

    def create_electronics(self, overrides: Optional[Dict[str, Any]] = None) -> FakeProduct:
        """创建电子产品"""
        electronics_overrides = {"category": "电子产品", **(overrides or {})}
        return self.create(electronics_overrides)

    def create_discounted(self, discount: float = 0.2, overrides: Optional[Dict[str, Any]] = None) -> FakeProduct:
        """创建打折产品"""
        product = self.create(overrides)
        product.price = round(product.price * (1 - discount), 2)
        return product

    def create_out_of_stock(self, overrides: Optional[Dict[str, Any]] = None) -> FakeProduct:
        """创建缺货产品"""
        out_of_stock_overrides = {"stock": 0, "is_available": False, **(overrides or {})}
        return self.create(out_of_stock_overrides)


class OrderFactory(TestDataFactory[FakeOrder]):
    """订单数据工厂"""

    STATUSES = ["pending", "confirmed", "processing", "shipped", "delivered", "cancelled"]
    PRODUCT_FACTORY = ProductFactory()

    def _generate_data(self) -> FakeOrder:
        # 生成订单产品
        product_count = self.random_int(1, 5)
        products = []
        total = 0.0

        for _ in range(product_count):
            product = self.PRODUCT_FACTORY.create()
            quantity = self.random_int(1, 3)
            item_total = product.price * quantity
            total += item_total
            products.append({
                "product_id": product.id,
                "name": product.name,
                "price": product.price,
                "quantity": quantity,
            })

        return FakeOrder(
            id=self.generate_uuid(),
            order_number=f"ORD-{datetime.now().strftime('%Y%m%d')}-{self.generate_random_string(6).upper()}",
            user_id=self.generate_uuid(),
            products=products,
            total_amount=round(total, 2),
            status=self.random_choice(self.STATUSES),
            shipping_address=f"{self.random_choice(['北京', '上海', '广州', '深圳', '杭州'])}市xxx区xxx街道xxx号",
            created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        )

    def _to_dict(self, data: FakeOrder) -> Dict[str, Any]:
        return asdict(data)

    def create_with_products(self, count: int, overrides: Optional[Dict[str, Any]] = None) -> FakeOrder:
        """创建包含指定数量产品的订单"""
        products = []
        total = 0.0

        for _ in range(count):
            product = self.PRODUCT_FACTORY.create()
            quantity = self.random_int(1, 3)
            total += product.price * quantity
            products.append({
                "product_id": product.id,
                "name": product.name,
                "price": product.price,
                "quantity": quantity,
            })

        order = self.create(overrides)
        order.products = products
        order.total_amount = round(total, 2)
        return order

    def create_pending(self, overrides: Optional[Dict[str, Any]] = None) -> FakeOrder:
        """创建待处理订单"""
        pending_overrides = {"status": "pending", **(overrides or {})}
        return self.create(pending_overrides)

    def create_delivered(self, overrides: Optional[Dict[str, Any]] = None) -> FakeOrder:
        """创建已送达订单"""
        delivered_overrides = {"status": "delivered", **(overrides or {})}
        return self.create(delivered_overrides)


# ==================== 便捷函数 ====================

def create_user_factory(config: Optional[FactoryConfig] = None) -> UserFactory:
    """创建用户工厂"""
    return UserFactory(config)


def create_product_factory(config: Optional[FactoryConfig] = None) -> ProductFactory:
    """创建产品工厂"""
    return ProductFactory(config)


def create_order_factory(config: Optional[FactoryConfig] = None) -> OrderFactory:
    """创建订单工厂"""
    return OrderFactory(config)
