"""会员等级与积分管理"""
from decimal import Decimal
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
from pydantic import BaseModel, Field
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_admin_user, get_db
from app.core.models.customer import Customer
from app.core.models.member import MemberLevel, MemberPointsLedger
from app.core.models.user import User
from app.core.services.tenant import resolve_public_tenant_id
from app.schemas.common import PageResult

router = APIRouter(prefix="/member-levels", tags=["会员等级"])
points_router = APIRouter(prefix="/customers", tags=["会员积分"])
store_router = APIRouter(prefix="/store/member-levels", tags=["前台会员等级"])


class MemberLevelBase(BaseModel):
    name: str = Field(..., max_length=80)
    code: str = Field(..., max_length=50)
    rank: int = 0
    discount_rate: Decimal = Field(Decimal("1.0000"), ge=0, le=1)
    points_multiplier: Decimal = Field(Decimal("1.0000"), ge=0)
    free_shipping_threshold: Optional[Decimal] = None
    upgrade_spend: Optional[Decimal] = None
    upgrade_orders: Optional[int] = None
    validity_days: Optional[int] = None
    is_active: bool = True
    description: Optional[str] = None


class MemberLevelCreate(MemberLevelBase):
    pass


class MemberLevelUpdate(BaseModel):
    name: Optional[str] = None
    code: Optional[str] = None
    rank: Optional[int] = None
    discount_rate: Optional[Decimal] = None
    points_multiplier: Optional[Decimal] = None
    free_shipping_threshold: Optional[Decimal] = None
    upgrade_spend: Optional[Decimal] = None
    upgrade_orders: Optional[int] = None
    validity_days: Optional[int] = None
    is_active: Optional[bool] = None
    description: Optional[str] = None


class MemberLevelOut(MemberLevelBase):
    id: int
    tenant_id: int

    model_config = {"from_attributes": True}


class PointsAdjustIn(BaseModel):
    change_amount: int
    reason: str = Field(..., max_length=80)
    note: Optional[str] = None


class PointsLedgerOut(BaseModel):
    id: int
    customer_id: int
    order_id: Optional[int] = None
    change_amount: int
    balance_after: int
    reason: str
    note: Optional[str] = None

    model_config = {"from_attributes": True}


@router.get("", response_model=PageResult[MemberLevelOut], summary="会员等级列表")
async def list_member_levels(
    page: int = Query(1, ge=1),
    page_size: int = Query(50, ge=1, le=100),
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    q = select(MemberLevel).where(MemberLevel.tenant_id == admin.tenant_id)
    total = (await db.execute(select(func.count()).select_from(q.subquery()))).scalar() or 0
    result = await db.execute(
        q.order_by(MemberLevel.rank.asc(), MemberLevel.id.asc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    return PageResult(items=result.scalars().all(), total=total, page=page, page_size=page_size)


@router.post("", response_model=MemberLevelOut, status_code=status.HTTP_201_CREATED, summary="创建会员等级")
async def create_member_level(
    body: MemberLevelCreate,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    dup = await db.execute(
        select(MemberLevel).where(MemberLevel.tenant_id == admin.tenant_id, MemberLevel.code == body.code)
    )
    if dup.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="该会员等级 code 已存在")
    level = MemberLevel(tenant_id=admin.tenant_id, **body.model_dump())
    level.is_active = 1 if body.is_active else 0
    db.add(level)
    await db.commit()
    await db.refresh(level)
    return level


@router.put("/{level_id}", response_model=MemberLevelOut, summary="更新会员等级")
async def update_member_level(
    level_id: int,
    body: MemberLevelUpdate,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(MemberLevel).where(MemberLevel.id == level_id, MemberLevel.tenant_id == admin.tenant_id)
    )
    level = result.scalar_one_or_none()
    if not level:
        raise HTTPException(status_code=404, detail="会员等级不存在")
    data = body.model_dump(exclude_unset=True)
    if "code" in data:
        dup = await db.execute(
            select(MemberLevel).where(
                MemberLevel.tenant_id == admin.tenant_id,
                MemberLevel.code == data["code"],
                MemberLevel.id != level_id,
            )
        )
        if dup.scalar_one_or_none():
            raise HTTPException(status_code=400, detail="该会员等级 code 已存在")
    for key, value in data.items():
        if key == "is_active":
            value = 1 if value else 0
        setattr(level, key, value)
    await db.commit()
    await db.refresh(level)
    return level


@router.delete("/{level_id}", status_code=status.HTTP_204_NO_CONTENT, summary="删除会员等级")
async def delete_member_level(
    level_id: int,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(MemberLevel).where(MemberLevel.id == level_id, MemberLevel.tenant_id == admin.tenant_id)
    )
    level = result.scalar_one_or_none()
    if not level:
        raise HTTPException(status_code=404, detail="会员等级不存在")
    await db.delete(level)
    await db.commit()


@points_router.post("/{customer_id}/points", response_model=PointsLedgerOut, summary="调整会员积分")
async def adjust_customer_points(
    customer_id: int,
    body: PointsAdjustIn,
    db: AsyncSession = Depends(get_db),
    admin: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(Customer).where(Customer.id == customer_id, Customer.tenant_id == admin.tenant_id)
    )
    customer = result.scalar_one_or_none()
    if not customer:
        raise HTTPException(status_code=404, detail="会员不存在")

    new_balance = int(customer.points_balance or 0) + body.change_amount
    if new_balance < 0:
        raise HTTPException(status_code=400, detail="积分余额不足")

    customer.points_balance = new_balance
    ledger = MemberPointsLedger(
        tenant_id=admin.tenant_id,
        customer_id=customer.id,
        change_amount=body.change_amount,
        balance_after=new_balance,
        reason=body.reason,
        note=body.note,
    )
    db.add(customer)
    db.add(ledger)
    await db.commit()
    await db.refresh(ledger)
    return ledger


@store_router.get("", response_model=list[MemberLevelOut], summary="前台会员等级列表")
async def store_list_member_levels(
    request: Request,
    tenant_id: Optional[int] = Query(None),
    db: AsyncSession = Depends(get_db),
):
    tid = await resolve_public_tenant_id(db, tenant_id=tenant_id, request=request)
    result = await db.execute(
        select(MemberLevel)
        .where(MemberLevel.tenant_id == tid, MemberLevel.is_active == 1)
        .order_by(MemberLevel.rank.asc(), MemberLevel.id.asc())
    )
    return result.scalars().all()
