"""客户管理路由"""
from typing import Optional
from decimal import Decimal
import bcrypt
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, or_

from pydantic import BaseModel
from app.api.deps import get_db, get_admin_user
from app.core.models.user import User
from app.core.models.customer import Customer
from app.core.models.member import MemberLevel
from app.core.models.order import Order
from app.core.models.customer_address import CustomerAddress
from app.schemas.common import PageResult
from app.schemas.customer import CustomerOut

router = APIRouter(prefix="/customers", tags=["客户管理"])


@router.get("", response_model=PageResult[CustomerOut], summary="客户列表")
async def list_customers(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    keyword: Optional[str] = None,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    tid = current_user.tenant_id
    q = select(Customer).where(Customer.tenant_id == tid)

    if keyword:
        q = q.where(or_(
            Customer.name.ilike(f"%{keyword}%"),
            Customer.email.ilike(f"%{keyword}%"),
            Customer.phone.ilike(f"%{keyword}%"),
        ))

    total_r = await db.execute(select(func.count()).select_from(q.subquery()))
    total = total_r.scalar() or 0

    q = q.order_by(Customer.created_at.desc()).offset((page - 1) * page_size).limit(page_size)
    result = await db.execute(q)
    customers = result.scalars().all()

    # 批量查询所有客户的默认地址（优先 is_default=1，其次最新一条）
    customer_ids = [c.id for c in customers]
    addr_map: dict[int, CustomerAddress] = {}
    if customer_ids:
        addr_r = await db.execute(
            select(CustomerAddress)
            .where(CustomerAddress.customer_id.in_(customer_ids))
            .order_by(CustomerAddress.is_default.desc(), CustomerAddress.id.desc())
        )
        for a in addr_r.scalars().all():
            if a.customer_id not in addr_map:
                addr_map[a.customer_id] = a

    # 批量查询会员等级名称，避免 N+1
    level_ids = list({c.member_level_id for c in customers if c.member_level_id})
    level_name_map: dict[int, str] = {}
    if level_ids:
        lvl_r = await db.execute(
            select(MemberLevel.id, MemberLevel.name).where(MemberLevel.id.in_(level_ids))
        )
        level_name_map = {row.id: row.name for row in lvl_r.all()}

    items = []
    for c in customers:
        # Count orders
        cnt_r = await db.execute(
            select(func.count(Order.id)).where(
                Order.customer_id == c.id,
                Order.tenant_id == tid,
            )
        )
        orders_count = cnt_r.scalar() or 0

        # Sum total spent (completed/paid orders)
        spent_r = await db.execute(
            select(func.coalesce(func.sum(Order.grand_total), 0)).where(
                Order.customer_id == c.id,
                Order.tenant_id == tid,
                Order.status.in_(["paid", "shipped", "completed"]),
            )
        )
        total_spent = spent_r.scalar() or Decimal("0")

        tier = level_name_map.get(c.member_level_id) or "regular"

        # 默认收货地址
        from app.schemas.customer import CustomerAddressBrief
        addr = addr_map.get(c.id)
        default_addr = CustomerAddressBrief(
            id=addr.id, name=addr.name, phone=addr.phone,
            province=addr.province, city=addr.city,
            district=addr.district, street=addr.street,
            is_default=bool(addr.is_default),
        ) if addr else None

        items.append(CustomerOut(
            id=c.id,
            name=c.name or "",
            email=c.email or "",
            phone=c.phone or "",
            orders_count=orders_count,
            total_spent=total_spent,
            membership_tier=tier,
            points_balance=c.points_balance or 0,
            member_level_id=c.member_level_id,
            member_level_name=level_name_map.get(c.member_level_id) if c.member_level_id else None,
            default_address=default_addr,
            created_at=c.created_at,
            is_active=c.is_active,
        ))

    return PageResult(items=items, total=total, page=page, page_size=page_size)


@router.get("/{customer_id}", response_model=CustomerOut, summary="客户详情")
async def get_customer(
    customer_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    r = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    c = r.scalar_one_or_none()
    if not c:
        raise HTTPException(404, "客户不存在")

    cnt_r = await db.execute(
        select(func.count(Order.id)).where(
            Order.customer_id == c.id,
            Order.tenant_id == current_user.tenant_id,
        )
    )
    orders_count = cnt_r.scalar() or 0

    spent_r = await db.execute(
        select(func.coalesce(func.sum(Order.grand_total), 0)).where(
            Order.customer_id == c.id,
            Order.tenant_id == current_user.tenant_id,
            Order.status.in_(["paid", "shipped", "completed"]),
        )
    )
    total_spent = spent_r.scalar() or Decimal("0")

    level_name = None
    if c.member_level_id:
        lvl_r = await db.execute(select(MemberLevel).where(MemberLevel.id == c.member_level_id))
        lvl = lvl_r.scalar_one_or_none()
        level_name = lvl.name if lvl else None

    tier = level_name or "regular"

    from app.core.models.tenant_settings import TenantSettings
    from app.core.services.customer_fields import normalize_fields, filter_profile_data
    ts_r = await db.execute(select(TenantSettings).where(TenantSettings.tenant_id == current_user.tenant_id))
    ts = ts_r.scalar_one_or_none()
    ts_extra = (ts.extra or {}) if ts else {}
    enabled_fields = normalize_fields(ts_extra.get("customer_profile_fields") or [])
    profile_data = filter_profile_data(c.extra_data or {}, enabled_fields)

    return CustomerOut(
        id=c.id,
        name=c.name or "",
        email=c.email or "",
        phone=c.phone or "",
        orders_count=orders_count,
        total_spent=total_spent,
        membership_tier=tier,
        points_balance=c.points_balance or 0,
        member_level_id=c.member_level_id,
        member_level_name=level_name,
        created_at=c.created_at,
        is_active=c.is_active,
        profile_data=profile_data if profile_data else None,
    )


class AdminProfileUpdate(BaseModel):
    profile_fields: Optional[dict] = None


@router.put("/{customer_id}/profile", summary="管理员更新客户自定义字段")
async def update_customer_profile(
    customer_id: int,
    body: AdminProfileUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    r = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    c = r.scalar_one_or_none()
    if not c:
        raise HTTPException(404, "客户不存在")

    from app.core.models.tenant_settings import TenantSettings
    from app.core.services.customer_fields import normalize_fields, filter_input, validate_required
    ts_r = await db.execute(select(TenantSettings).where(TenantSettings.tenant_id == current_user.tenant_id))
    ts = ts_r.scalar_one_or_none()
    ts_extra = (ts.extra or {}) if ts else {}
    enabled_fields = normalize_fields(ts_extra.get("customer_profile_fields") or [])

    warnings: list[str] = []
    if body.profile_fields and enabled_fields:
        clean = filter_input(body.profile_fields, enabled_fields)
        missing = validate_required(clean, enabled_fields)
        if missing:
            warnings = [f"必填字段未填写: {', '.join(missing)}"]
        current = dict(c.extra_data or {})
        current.update(clean)
        c.extra_data = current
        db.add(c)
        await db.commit()
        await db.refresh(c)

    from app.core.services.customer_fields import filter_profile_data
    profile_data = filter_profile_data(c.extra_data or {}, enabled_fields)
    return {"profile_data": profile_data, "warnings": warnings}


class SetMemberLevelIn(BaseModel):
    member_level_id: Optional[int] = None


@router.put("/{customer_id}/member-level", summary="设置客户会员等级")
async def set_customer_member_level(
    customer_id: int,
    body: SetMemberLevelIn,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    r = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    c = r.scalar_one_or_none()
    if not c:
        raise HTTPException(404, "客户不存在")

    if body.member_level_id is not None:
        lvl_r = await db.execute(
            select(MemberLevel).where(
                MemberLevel.id == body.member_level_id,
                MemberLevel.tenant_id == current_user.tenant_id,
            )
        )
        if not lvl_r.scalar_one_or_none():
            raise HTTPException(404, "会员等级不存在")

    c.member_level_id = body.member_level_id
    await db.commit()
    return {"message": "会员等级已更新", "member_level_id": body.member_level_id}


@router.get("/{customer_id}/addresses", summary="获取客户收货地址列表")
async def get_customer_addresses(
    customer_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    """管理员查看指定客户的收货地址，用于建单时选用"""
    cr = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    if not cr.scalar_one_or_none():
        raise HTTPException(404, "客户不存在")

    ar = await db.execute(
        select(CustomerAddress)
        .where(CustomerAddress.customer_id == customer_id)
        .order_by(CustomerAddress.is_default.desc(), CustomerAddress.sort_order, CustomerAddress.id)
    )
    addrs = ar.scalars().all()
    return [
        {
            "id":           a.id,
            "name":         a.name,
            "phone":        a.phone,
            "country":      a.country,
            "zip_code":     a.zip_code,
            "province":     a.province,
            "city":         a.city,
            "district":     a.district,
            "street":       a.street,
            "is_default":   bool(a.is_default),
            "extra_fields": a.extra_fields or {},
        }
        for a in addrs
    ]


class AdminAddressCreate(BaseModel):
    name: str
    phone: str
    country: str = "NZ"
    zip_code: str = ""
    province: str
    city: str
    district: str = ""
    street: str
    is_default: bool = False
    extra_fields: dict = {}


class AdminAddressUpdate(BaseModel):
    name: Optional[str] = None
    phone: Optional[str] = None
    country: Optional[str] = None
    zip_code: Optional[str] = None
    province: Optional[str] = None
    city: Optional[str] = None
    district: Optional[str] = None
    street: Optional[str] = None
    is_default: Optional[bool] = None
    extra_fields: Optional[dict] = None


@router.post("/{customer_id}/addresses", summary="新增客户收货地址")
async def create_customer_address(
    customer_id: int,
    body: AdminAddressCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    cr = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    if not cr.scalar_one_or_none():
        raise HTTPException(404, "客户不存在")

    if body.is_default:
        await db.execute(
            CustomerAddress.__table__.update()
            .where(CustomerAddress.customer_id == customer_id)
            .values(is_default=0)
        )

    addr = CustomerAddress(
        tenant_id=current_user.tenant_id,
        customer_id=customer_id,
        name=body.name,
        phone=body.phone,
        country=body.country,
        zip_code=body.zip_code,
        province=body.province,
        city=body.city,
        district=body.district or "",
        street=body.street,
        is_default=1 if body.is_default else 0,
        extra_fields=body.extra_fields or {},
    )
    db.add(addr)
    await db.commit()
    await db.refresh(addr)
    return {
        "id": addr.id, "name": addr.name, "phone": addr.phone,
        "country": addr.country, "zip_code": addr.zip_code,
        "province": addr.province, "city": addr.city,
        "district": addr.district, "street": addr.street,
        "is_default": bool(addr.is_default),
        "extra_fields": addr.extra_fields or {},
    }


@router.put("/{customer_id}/addresses/{address_id}", summary="更新客户收货地址")
async def update_customer_address(
    customer_id: int,
    address_id: int,
    body: AdminAddressUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    cr = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    if not cr.scalar_one_or_none():
        raise HTTPException(404, "客户不存在")

    ar = await db.execute(
        select(CustomerAddress).where(
            CustomerAddress.id == address_id,
            CustomerAddress.customer_id == customer_id,
        )
    )
    addr = ar.scalar_one_or_none()
    if not addr:
        raise HTTPException(404, "地址不存在")

    if body.is_default:
        await db.execute(
            CustomerAddress.__table__.update()
            .where(CustomerAddress.customer_id == customer_id)
            .values(is_default=0)
        )

    update_data = body.model_dump(exclude_unset=True)
    for k, v in update_data.items():
        if k == "is_default":
            setattr(addr, k, 1 if v else 0)
        else:
            setattr(addr, k, v)

    await db.commit()
    await db.refresh(addr)
    return {
        "id": addr.id, "name": addr.name, "phone": addr.phone,
        "country": addr.country, "zip_code": addr.zip_code,
        "province": addr.province, "city": addr.city,
        "district": addr.district, "street": addr.street,
        "is_default": bool(addr.is_default),
        "extra_fields": addr.extra_fields or {},
    }


@router.delete("/{customer_id}/addresses/{address_id}", status_code=204, summary="删除客户收货地址")
async def delete_customer_address(
    customer_id: int,
    address_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    cr = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    if not cr.scalar_one_or_none():
        raise HTTPException(404, "客户不存在")

    ar = await db.execute(
        select(CustomerAddress).where(
            CustomerAddress.id == address_id,
            CustomerAddress.customer_id == customer_id,
        )
    )
    addr = ar.scalar_one_or_none()
    if not addr:
        raise HTTPException(404, "地址不存在")

    await db.delete(addr)
    await db.commit()


class CustomerCreateIn(BaseModel):
    name: str
    email: str
    phone: Optional[str] = None
    password: Optional[str] = None
    is_active: int = 1


@router.post("", summary="新增客户", status_code=201)
async def create_customer(
    body: CustomerCreateIn,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    existing = await db.execute(
        select(Customer).where(
            Customer.tenant_id == current_user.tenant_id,
            Customer.email == body.email,
        )
    )
    if existing.scalar_one_or_none():
        raise HTTPException(400, "该邮箱已被注册")

    extra_data = {}
    if body.password:
        if len(body.password) < 8:
            raise HTTPException(422, "密码长度不能少于 8 位")
        extra_data["password_hash"] = bcrypt.hashpw(body.password.encode(), bcrypt.gensalt()).decode()

    c = Customer(
        tenant_id=current_user.tenant_id,
        name=body.name,
        email=body.email,
        phone=body.phone,
        is_active=body.is_active,
        extra_data=extra_data or None,
    )
    db.add(c)
    await db.commit()
    await db.refresh(c)
    return {"id": c.id, "message": "客户已创建"}


@router.delete("/{customer_id}", status_code=204, summary="删除客户")
async def delete_customer(
    customer_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    r = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    c = r.scalar_one_or_none()
    if not c:
        raise HTTPException(404, "客户不存在")

    cnt_r = await db.execute(
        select(func.count(Order.id)).where(
            Order.customer_id == customer_id,
            Order.tenant_id == current_user.tenant_id,
        )
    )
    if (cnt_r.scalar() or 0) > 0:
        raise HTTPException(400, "该客户存在订单记录，无法删除")

    await db.execute(
        CustomerAddress.__table__.delete().where(CustomerAddress.customer_id == customer_id)
    )
    await db.delete(c)
    await db.commit()


class CustomerUpdateIn(BaseModel):
    name: Optional[str] = None
    phone: Optional[str] = None
    is_active: Optional[int] = None
    password: Optional[str] = None


@router.put("/{customer_id}", summary="更新客户基本信息")
async def update_customer(
    customer_id: int,
    body: CustomerUpdateIn,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    r = await db.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.tenant_id == current_user.tenant_id,
        )
    )
    c = r.scalar_one_or_none()
    if not c:
        raise HTTPException(404, "客户不存在")

    if body.name is not None:
        c.name = body.name
    if body.phone is not None:
        c.phone = body.phone
    if body.is_active is not None:
        c.is_active = body.is_active
    if body.password is not None:
        if len(body.password) < 8:
            raise HTTPException(422, "密码长度不能少于 8 位")
        pwd_hash = bcrypt.hashpw(body.password.encode(), bcrypt.gensalt()).decode()
        c.set_attribute("password_hash", pwd_hash)

    await db.commit()
    return {"message": "客户信息已更新"}