import aiohttp
from typing import Optional, Dict, Any, List
from pydantic import BaseModel, Field, computed_field
from enum import Enum
import json
from asgiref.sync import sync_to_async


class Product(BaseModel):
    """产品模型 - 请在此填入你的字段"""
    uid: str
    rowid: str
    name: str
    pieces: int | None
    segment_size: int | None
    unit: str | None
    color: str | None
    width: str | None = None
    detail_str: str | None = Field(exclude=True)  # 在序列化时排除此字段
    created_at: str

    @computed_field
    @property
    def detail(self) -> dict[str, Any]:
        """将 detail_str 转换为字典"""
        try:
            return json.loads(self.detail_str) if self.detail_str else {}
        except (json.JSONDecodeError, TypeError):
            return {}


class ProductListResponse(BaseModel):
    """产品列表响应"""
    products: List[Product]
    total: int


mdy_table_map = {
	'product': 'spmx',
	'customer': 'quanbu',
}


class HTTPMethod(Enum):
    """HTTP 请求方法枚举"""
    GET = "GET"
    POST = "POST"


class MingDaoYunClient:
    """明道云 API 客户端"""

    def __init__(self, app_key: str, sign: str, base_url: str = ""):
        """
        初始化客户端

        Args:
            app_key: 应用密钥
            sign: 签名
            base_url: API 基础地址
        """
        self.app_key = app_key
        self.sign = sign
        self.base_url = base_url

    async def request(
        self,
        method: HTTPMethod,
        endpoint: str,
        data: Optional[Dict[str, Any]] = None,
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> Any:
        """
        通用异步请求函数

        Args:
            method: 请求方法 (GET/POST)
            endpoint: API 端点路径
            data: POST 请求体数据（JSON）
            params: URL 查询参数
            headers: 自定义请求头

        Returns:
            响应 JSON 数据

        Raises:
            aiohttp.ClientError: 请求失败时抛出
        """
        url = f"{self.base_url}{endpoint}"

        # 构建默认请求头
        default_headers = {
            "Content-Type": "application/json",
        }

        if headers:
            default_headers.update(headers)

        # 添加认证参数
        auth_params = {
            "appKey": self.app_key,
            "sign": self.sign
        }

        async with aiohttp.ClientSession() as session:
            if method == HTTPMethod.GET:
                async with session.get(url, params=params, json=auth_params) as response:
                    response.raise_for_status()
                    return await response.json()

            elif method == HTTPMethod.POST:
                if data is None:
                    data = {}

                data.update(auth_params)
                async with session.post(url, json=data) as response:
                    response.raise_for_status()
                    return await response.json()

            else:
                raise ValueError(f"Unsupported HTTP method: {method}")

    async def get(
        self,
        endpoint: str,
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> Any:
        """
        发送 GET 请求

        Args:
            endpoint: API 端点路径
            params: URL 查询参数
            headers: 自定义请求头

        Returns:
            响应 JSON 数据
        """
        return await self.request(
            method=HTTPMethod.GET,
            endpoint=endpoint,
            params=params,
            headers=headers,
        )

    async def post(
        self,
        endpoint: str,
        data: Optional[Dict[str, Any]] = None,
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> Any:
        """
        发送 POST 请求

        Args:
            endpoint: API 端点路径
            data: POST 请求体数据（JSON）
            params: URL 查询参数
            headers: 自定义请求头

        Returns:
            响应 JSON 数据
        """
        return await self.request(
            method=HTTPMethod.POST,
            endpoint=endpoint,
            data=data,
            params=params,
            headers=headers,
        )


product_type_map = {
    'name': '668caa5eb80969563ecaee7d',
    'pieces': '689c5aa37c175367b29fcb87',
    'color': '66ed3b9ae01d5599bdb45f6d',
    'uid': '668caa5eb80969563ecaee7c',
    'unit': '668e2ee2ca758c8cc5d0dc1d',
    'segment_size': '668e2194790c0e04058b4f3c',
    'width': '668e2194790c0e04058b4f3c',
    'detail_str': '668caa5eb80969563ecaee7e',
    'created_at': 'ctime',
    'rowid': 'rowid',
}

customer_type_map = {
    'name': '62d52f4b8d2972284492dcf9',
    'area': '62d52f4b8d2972284492dd09',
    'created_at': 'ctime',
    'rowid': 'rowid',
    'uid': '668bb9370207cf7520fe551e',
}

class Customer(BaseModel):
    """客户模型 - 请在此填入你的字段"""
    uid: str
    rowid: str
    name: str
    area: str | None
    created_at: str


def pick_customer(fields: dict) -> Customer:
    """从字段字典中提取客户信息"""
    data = {k: fields.get(v, '') for k, v in customer_type_map.items()}
    return Customer(**data)


# json param example:
# {
#     "appKey": "208e55fea5cea59f",
#     "sign": "MWU0YmViYjkwZmM1ZDIzYzRiN2U3ZGQ4MmE4ZGNkMjc0MWM1ZmQ2ZjkwMjljODE4YmNkZTBhMzA0OTU2YzE2NA==",
#     "worksheetId": "quanbu",
#     "listType": 1,
#     "sortId": "ctime",
#     "isAsc": false,
#     "notGetTotal": true
# }


def pick_product(fields: dict) -> Product:
    """
    从字段字典中提取产品信息
    """
    data = {k: fields.get(v, '') for k, v in product_type_map.items()}

    def _to_int(value):
        if value in ('', None):
            return None
        try:
            return int(value)
        except (TypeError, ValueError):
            return None

    data['pieces'] = _to_int(data.get('pieces'))
    data['segment_size'] = _to_int(data.get('segment_size'))

    return Product(**data)


async def fetch_products_from_mingdaoyun(page: int = 1, page_size: int = 100) -> tuple[list[Product], int]:
    """
    从明道云获取产品列表

    Returns:
        tuple: (产品列表, 总数量)
    """
    client = MingDaoYunClient(
        app_key='208e55fea5cea59f',
        sign='MWU0YmViYjkwZmM1ZDIzYzRiN2U3ZGQ4MmE4ZGNkMjc0MWM1ZmQ2ZjkwMjljODE4YmNkZTBhMzA0OTU2YzE2NA==',
        base_url="https://api.mingdao.com"
    )
    response = await client.post(
        endpoint='/v2/open/worksheet/getFilterRows',
        data={
            'worksheetId': 'spmx',
            'pageIndex': page,
            'pageSize': page_size,
            'sortId': 'ctime',
            'isAsc': True,
        }
    )
    data = response.get('data')
    if data:
        print(f'[product-sync] page={page} size={page_size} rows={len(data.get("rows", []))} total={data.get("total")}')
    else:
        print(f'[product-sync] page={page} size={page_size} received empty data')
    if not data:
        return [], 0

    products = [pick_product(item) for item in data.get('rows', [])]
    total_count = data.get('total', 0)
    return products, total_count


async def fetch_customers_from_mingdaoyun(page: int = 1, page_size: int = 100) -> tuple[list[Customer], int]:
    """
    从明道云获取客户列表
    """
    client = MingDaoYunClient(
        app_key='208e55fea5cea59f',
        sign='MWU0YmViYjkwZmM1ZDIzYzRiN2U3ZGQ4MmE4ZGNkMjc0MWM1ZmQ2ZjkwMjljODE4YmNkZTBhMzA0OTU2YzE2NA==',
        base_url="https://api.mingdao.com"
    )
    response = await client.post(
        endpoint='/v2/open/worksheet/getFilterRows',
        data={
            'worksheetId': 'quanbu',
            'pageIndex': page,
            'pageSize': page_size,
            'sortId': 'ctime',
            'isAsc': True,
        }
    )
    data = response.get('data')
    if data:
        print(f'[customer-sync] page={page} size={page_size} rows={len(data.get("rows", []))} total={data.get("total")}')
    else:
        print(f'[customer-sync] page={page} size={page_size} received empty data')
    if not data:
        return [], 0

    customers = [pick_customer(item) for item in data.get('rows', [])]
    total_count = data.get('total', 0)
    return customers, total_count


fabric_type_map = {
    'name': '62d52f4b8d2972284492de61',
}


class Fabric(BaseModel):
    """面料模型 - 请在此填入你的字段"""
    name: str


def pick_fabric(fields: dict) -> Fabric:
    """
    从字段字典中提取面料信息
    """
    data = {k: fields.get(v, '') for k, v in fabric_type_map.items()}
    return Fabric(**data)


async def sync_fabric_from_mingdaoyun(page: int = 1, page_size: int = 100) -> int:
    """
    从明道云同步面料数据
    """
    client = MingDaoYunClient(
        app_key='208e55fea5cea59f',
        sign='MWU0YmViYjkwZmM1ZDIzYzRiN2U3ZGQ4MmE4ZGNkMjc0MWM1ZmQ2ZjkwMjljODE4YmNkZTBhMzA0OTU2YzE2NA==',
        base_url="https://api.mingdao.com"
    )
    response = await client.post(
        endpoint='/v2/open/worksheet/getFilterRows',
        data={
            'worksheetId': '668ba100fb551c850214067d',
            'pageIndex': page,
            'pageSize': page_size,
            'sortId': 'ctime',
            'isAsc': False,
        }
    )
    data = response.get('data')
    if data:
        rows = data.get("rows", [])
        print(f'[fabric-sync] fetch rows={len(rows)} total={data.get("total")}')
        if rows:
            print(f'[fabric-sync] first row keys: {list(rows[0].keys())[:10]}')
            print(f'[fabric-sync] first row sample: {rows[0]}')
    else:
        print(f'[fabric-sync] fetch empty data (page={page}, size={page_size})')
    if not data:
        return [], 0
    fabrics = [pick_fabric(item) for item in data.get('rows', [])]
    total_count = data.get('total', 0)
    await sync_to_async(_create_fabric_quick_inputs)(
        page,
        page_size,
        fabrics
    )
    return total_count


def _create_fabric_quick_inputs(page: int, page_size: int, fabrics: list[Fabric]) -> None:
    from basic_info import models as basic_models
    total = len(fabrics)
    created_count = 0
    sample_names = [fabric.name for fabric in fabrics[:5]]
    print(f'[fabric-sync] page={page} size={page_size} fetched={total}')
    print(f'[fabric-sync] sample names: {sample_names}')
    for fabric in fabrics:
        if not fabric.name:
            continue
        obj, created = basic_models.QuickInput.objects.update_or_create(
            name=fabric.name,
            group='布料名',
            defaults={'value': fabric.name},
        )
        if created:
            created_count += 1
    print(f'[fabric-sync] page={page} new_records={created_count} updated_or_existing={total - created_count}')
