"""后台代理管理路由"""
from datetime import datetime, timezone

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select, func, or_
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db
from app.core.deps import require_role
from app.models import (
    AgentEvaluationLog,
    AgentRiskEvent,
    AgentStatusLog,
    AgentTier,
    AgentSettlement,
    AffiliateClick,
    Order,
    User,
    UserAgent,
)
from app.models.order import OrderStatus
from app.models.user_agent import AgentStatus
from app.schemas.agent import (
    AgentTierCreate,
    AgentTierResponse,
    AgentTierUpdate,
    AgentReviewRequest,
    AgentManualActionRequest,
    AgentTierAssignRequest,
    AgentSettlementResponse,
    UserAgentResponse,
)
from app.schemas.common import ApiResponse
from app.services import agent_lifecycle_service

router = APIRouter()
_admin = require_role("admin", "super_admin")


@router.get("/agent-tiers", response_model=ApiResponse)
async def list_agent_tiers(_: User = Depends(_admin), db: AsyncSession = Depends(get_db)):
    res = await db.execute(select(AgentTier).order_by(AgentTier.sort_order, AgentTier.id))
    tiers = res.scalars().all()
    return ApiResponse(data=[AgentTierResponse.model_validate(t) for t in tiers])


@router.post("/agent-tiers", response_model=ApiResponse)
async def create_agent_tier(body: AgentTierCreate, _: User = Depends(_admin), db: AsyncSession = Depends(get_db)):
    existing = await db.execute(select(AgentTier).where(AgentTier.code == body.code))
    if existing.scalar_one_or_none():
        raise HTTPException(400, f"档位标识 {body.code} 已存在")
    tier = AgentTier(**body.model_dump())
    db.add(tier)
    await db.flush()
    await db.refresh(tier)
    return ApiResponse(data=AgentTierResponse.model_validate(tier))


@router.put("/agent-tiers/{tier_id}", response_model=ApiResponse)
async def update_agent_tier(tier_id: int, body: AgentTierUpdate, _: User = Depends(_admin), db: AsyncSession = Depends(get_db)):
    tier = await db.get(AgentTier, tier_id)
    if not tier:
        raise HTTPException(404, "档位不存在")
    for key, val in body.model_dump(exclude_none=True).items():
        setattr(tier, key, val)
    await db.flush()
    await db.refresh(tier)
    return ApiResponse(data=AgentTierResponse.model_validate(tier))


@router.delete("/agent-tiers/{tier_id}", response_model=ApiResponse)
async def delete_agent_tier(tier_id: int, _: User = Depends(_admin), db: AsyncSession = Depends(get_db)):
    tier = await db.get(AgentTier, tier_id)
    if not tier:
        raise HTTPException(404, "档位不存在")
    res = await db.execute(select(func.count()).select_from(UserAgent).where(UserAgent.agent_tier_id == tier_id))
    count = res.scalar() or 0
    if count > 0:
        raise HTTPException(400, f"有 {count} 个代理使用此档位，无法删除")
    await db.delete(tier)
    await db.flush()
    return ApiResponse(data={"ok": True})


@router.get("/agents", response_model=ApiResponse)
async def list_agents(
    filter_status: str | None = Query(None),
    keyword: str | None = Query(None),
    offset: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=100),
    _: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    q = select(UserAgent)
    if filter_status:
        q = q.where(UserAgent.status == filter_status)
    if keyword:
        user_q = select(User.id).where(or_(User.username.contains(keyword), User.email.contains(keyword)))
        user_ids = (await db.execute(user_q)).scalars().all()
        if user_ids:
            q = q.where(UserAgent.user_id.in_(user_ids))
        else:
            q = q.where(UserAgent.user_id == -1)

    q = q.order_by(UserAgent.id.desc())
    total_q = select(func.count()).select_from(q.subquery())
    total = (await db.execute(total_q)).scalar() or 0
    res = await db.execute(q.offset(offset).limit(limit))
    agents = res.scalars().all()
    return ApiResponse(data={"items": [UserAgentResponse.model_validate(a) for a in agents], "total": total})


@router.get("/agents/{agent_id}", response_model=ApiResponse)
async def get_agent_detail(
    agent_id: int,
    _: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    """获取代理详情，包括关联的工单消息"""
    agent = await db.get(UserAgent, agent_id)
    if not agent:
        raise HTTPException(404, "代理记录不存在")

    from app.models.ticket import Ticket, TicketMessage, TicketDepartment

    # 查找关联的代理申请工单
    dept_res = await db.execute(
        select(TicketDepartment.id).where(TicketDepartment.code.like("agent_%"))
    )
    agent_dept_ids = [row[0] for row in dept_res.fetchall()]

    tickets_messages = []
    if agent_dept_ids:
        ticket_res = await db.execute(
            select(Ticket).where(
                Ticket.user_id == agent.user_id,
                Ticket.department_id.in_(agent_dept_ids),
            ).order_by(Ticket.id.desc())
        )
        for t in ticket_res.scalars().all():
            msg_res = await db.execute(
                select(TicketMessage).where(
                    TicketMessage.ticket_id == t.id,
                    TicketMessage.is_internal == False,
                ).order_by(TicketMessage.id.asc())
            )
            msgs = msg_res.scalars().all()
            tickets_messages.append({
                "ticket_id": t.id,
                "ticket_no": t.ticket_no,
                "subject": t.subject,
                "status": t.status.value if t.status else None,
                "created_at": t.created_at.isoformat() if t.created_at else None,
                "messages": [
                    {
                        "id": m.id,
                        "content": m.content,
                        "sender_type": m.sender_type.value if m.sender_type else None,
                        "created_at": m.created_at.isoformat() if m.created_at else None,
                    }
                    for m in msgs
                ],
            })

    data = UserAgentResponse.model_validate(agent).model_dump()
    data["tickets"] = tickets_messages
    evaluation_rows = (
        await db.execute(
            select(AgentEvaluationLog)
            .where(AgentEvaluationLog.agent_id == agent.id)
            .order_by(AgentEvaluationLog.id.desc())
            .limit(20)
        )
    ).scalars().all()
    status_rows = (
        await db.execute(
            select(AgentStatusLog)
            .where(AgentStatusLog.agent_id == agent.id)
            .order_by(AgentStatusLog.id.desc())
            .limit(20)
        )
    ).scalars().all()
    risk_rows = (
        await db.execute(
            select(AgentRiskEvent)
            .where(AgentRiskEvent.agent_id == agent.id)
            .order_by(AgentRiskEvent.id.desc())
            .limit(20)
        )
    ).scalars().all()
    data["evaluation_logs"] = [
        {
            "id": item.id,
            "net_sales": item.net_sales,
            "gross_sales": item.gross_sales,
            "refund_amount": item.refund_amount,
            "refund_rate_bps": item.refund_rate_bps,
            "active_customers": item.active_customers,
            "subsidy_loss": item.subsidy_loss,
            "agent_balance": item.agent_balance,
            "passed": bool(item.passed),
            "risk_locked": bool(item.risk_locked),
            "action": item.action,
            "reason": item.reason,
            "created_at": item.created_at.isoformat() if item.created_at else None,
        }
        for item in evaluation_rows
    ]
    data["status_logs"] = [
        {
            "id": item.id,
            "source": item.source,
            "action": item.action,
            "before_status": item.before_status,
            "after_status": item.after_status,
            "before_tier_id": item.before_tier_id,
            "after_tier_id": item.after_tier_id,
            "reason": item.reason,
            "operator_id": item.operator_id,
            "created_at": item.created_at.isoformat() if item.created_at else None,
        }
        for item in status_rows
    ]
    data["risk_events"] = [
        {
            "id": item.id,
            "event_type": item.event_type,
            "severity": item.severity,
            "status": item.status,
            "reason": item.reason,
            "created_at": item.created_at.isoformat() if item.created_at else None,
        }
        for item in risk_rows
    ]
    return ApiResponse(data=data)


@router.post("/agents/{agent_id}/review", response_model=ApiResponse)
async def review_agent(
    agent_id: int,
    body: AgentReviewRequest,
    admin_user: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    agent = await db.get(UserAgent, agent_id)
    if not agent:
        raise HTTPException(404, "代理记录不存在")

    review_message = (body.remark or "").strip()
    if not review_message:
        raise HTTPException(400, "请填写审核备注")

    if body.action == "approve":
        if not body.agent_tier_id:
            raise HTTPException(400, "请指定代理档位")
        tier = await db.get(AgentTier, body.agent_tier_id)
        if not tier:
            raise HTTPException(400, "代理档位不存在")
        agent.status = AgentStatus.ACTIVE
        agent.agent_tier_id = tier.id
        agent.approved_at = datetime.now(timezone.utc)
        agent.approved_by = admin_user.id
        agent.review_message = review_message

        from app.services.membership_service import get_or_create_membership
        membership = await get_or_create_membership(db, agent.user_id)
        membership.agent_tier = tier.code
    elif body.action == "reject":
        agent.status = AgentStatus.REJECTED
        agent.reject_reason = body.reject_reason or review_message
        agent.review_message = review_message
    else:
        raise HTTPException(400, "action 必须是 approve 或 reject")

    if body.remark:
        agent.remark = body.remark

    # ── 关闭关联的代理申请工单 ──
    from app.models.ticket import TicketDepartment, Ticket, TicketStatus, TicketMessage, TicketSenderType
    dept_res = await db.execute(
        select(TicketDepartment.id).where(TicketDepartment.code.like("agent_%"))
    )
    agent_dept_ids = [row[0] for row in dept_res.fetchall()]
    if agent_dept_ids:
        ticket_res = await db.execute(
            select(Ticket).where(
                Ticket.user_id == agent.user_id,
                Ticket.department_id.in_(agent_dept_ids),
                Ticket.status.in_([TicketStatus.OPEN, TicketStatus.PENDING, TicketStatus.PROCESSING, TicketStatus.WAITING_USER, TicketStatus.ANSWERED]),
            )
        )
        for t in ticket_res.scalars().all():
            t.status = TicketStatus.CLOSED
            t.closed_at = datetime.now(timezone.utc)
            msg = TicketMessage(
                ticket_id=t.id,
                sender_type=TicketSenderType.SYSTEM,
                content=f"代理申请已处理：{review_message}",
            )
            db.add(msg)

    await db.flush()
    await db.refresh(agent)
    return ApiResponse(data=UserAgentResponse.model_validate(agent))


@router.put("/agents/{agent_id}/tier", response_model=ApiResponse)
async def assign_agent_tier(
    agent_id: int,
    body: AgentTierAssignRequest,
    admin_user: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    agent = await db.get(UserAgent, agent_id)
    if not agent:
        raise HTTPException(404, "代理记录不存在")
    tier = await db.get(AgentTier, body.agent_tier_id)
    if not tier:
        raise HTTPException(400, "代理档位不存在")
    agent.agent_tier_id = tier.id

    from app.services.membership_service import get_or_create_membership
    membership = await get_or_create_membership(db, agent.user_id)
    membership.agent_tier = tier.code

    await db.flush()
    await db.refresh(agent)
    return ApiResponse(data=UserAgentResponse.model_validate(agent))


@router.post("/agents/{agent_id}/evaluate", response_model=ApiResponse)
async def evaluate_agent_now(
    agent_id: int,
    _: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    agent = await db.get(UserAgent, agent_id)
    if not agent:
        raise HTTPException(404, "代理记录不存在")
    result = await agent_lifecycle_service.evaluate_agent(db, agent, force=True)
    await db.refresh(agent)
    return ApiResponse(data={"agent": UserAgentResponse.model_validate(agent).model_dump(), "evaluation": result})


@router.post("/agents/{agent_id}/action", response_model=ApiResponse)
async def manual_agent_action(
    agent_id: int,
    body: AgentManualActionRequest,
    admin_user: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    agent = await db.get(UserAgent, agent_id)
    if not agent:
        raise HTTPException(404, "代理记录不存在")
    tier = None
    if body.agent_tier_id:
        tier = await db.get(AgentTier, body.agent_tier_id)
        if not tier:
            raise HTTPException(400, "代理档位不存在")
    try:
        await agent_lifecycle_service.manual_agent_action(
            db,
            agent,
            action=body.action,
            reason=body.reason,
            operator_id=admin_user.id,
            tier=tier,
        )
    except ValueError as exc:
        raise HTTPException(400, str(exc)) from exc
    await db.refresh(agent)
    return ApiResponse(data=UserAgentResponse.model_validate(agent))


@router.get("/agent-settlements", response_model=ApiResponse)
async def list_agent_settlements(
    settlement_type: str | None = Query(None),
    status: str | None = Query(None),
    user_id: int | None = Query(None),
    order_id: int | None = Query(None),
    offset: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=100),
    _: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    q = select(AgentSettlement)
    if settlement_type:
        q = q.where(AgentSettlement.settlement_type == settlement_type)
    if status:
        q = q.where(AgentSettlement.status == status)
    if user_id:
        q = q.where(AgentSettlement.user_id == user_id)
    if order_id:
        q = q.where(AgentSettlement.order_id == order_id)
    q = q.order_by(AgentSettlement.id.desc())
    total_q = select(func.count()).select_from(q.subquery())
    total = (await db.execute(total_q)).scalar() or 0
    res = await db.execute(q.offset(offset).limit(limit))
    settlements = res.scalars().all()
    return ApiResponse(data={"items": [AgentSettlementResponse.model_validate(s) for s in settlements], "total": total})


@router.get("/affiliate/report", response_model=ApiResponse)
async def affiliate_report(
    recent_limit: int = Query(50, ge=1, le=200),
    max_rows: int = Query(5000, ge=100, le=20000),
    _: User = Depends(_admin),
    db: AsyncSession = Depends(get_db),
):
    total_clicks = (await db.execute(select(func.count()).select_from(AffiliateClick))).scalar() or 0
    unique_ips = (
        await db.execute(select(func.count(func.distinct(AffiliateClick.ip))).where(AffiliateClick.ip.is_not(None)))
    ).scalar() or 0
    registrations = (
        await db.execute(
            select(func.count(func.distinct(AffiliateClick.registered_user_id))).where(
                AffiliateClick.registered_user_id.is_not(None)
            )
        )
    ).scalar() or 0
    paid_order_filter = (
        Order.aff_code.is_not(None),
        Order.status == OrderStatus.PAID,
    )
    paid_orders = (
        await db.execute(select(func.count()).select_from(Order).where(*paid_order_filter))
    ).scalar() or 0
    revenue = (
        await db.execute(
            select(func.coalesce(func.sum(Order.total_amount - Order.discount_amount), 0)).where(*paid_order_filter)
        )
    ).scalar() or 0

    click_rows = (
        await db.execute(select(AffiliateClick).order_by(AffiliateClick.id.desc()).limit(max_rows))
    ).scalars().all()

    channels: dict[tuple[str, str, str, str], dict] = {}
    attribution: dict[tuple[int, str], tuple[str, str, str, str]] = {}

    for click in click_rows:
        key = (
            str(click.aff_code or "").upper(),
            click.utm_source or "",
            click.utm_medium or "",
            click.utm_campaign or "",
        )
        item = channels.setdefault(
            key,
            {
                "aff_code": key[0],
                "utm_source": key[1] or None,
                "utm_medium": key[2] or None,
                "utm_campaign": key[3] or None,
                "clicks": 0,
                "registrations": set(),
                "orders": 0,
                "revenue": 0,
                "latest_click_at": None,
            },
        )
        item["clicks"] += 1
        if click.registered_user_id:
            item["registrations"].add(int(click.registered_user_id))
            attribution[(int(click.registered_user_id), key[0])] = key
        if not item["latest_click_at"] or click.created_at > item["latest_click_at"]:
            item["latest_click_at"] = click.created_at

    order_rows = (
        await db.execute(
            select(Order)
            .where(*paid_order_filter)
            .order_by(Order.id.desc())
            .limit(max_rows)
        )
    ).scalars().all()
    for order in order_rows:
        aff_code = str(order.aff_code or "").upper()
        key = attribution.get((int(order.user_id), aff_code), (aff_code, "", "", ""))
        item = channels.setdefault(
            key,
            {
                "aff_code": key[0],
                "utm_source": key[1] or None,
                "utm_medium": key[2] or None,
                "utm_campaign": key[3] or None,
                "clicks": 0,
                "registrations": set(),
                "orders": 0,
                "revenue": 0,
                "latest_click_at": None,
            },
        )
        item["orders"] += 1
        item["revenue"] += max(0, int(order.total_amount or 0) - int(order.discount_amount or 0))

    channel_items = []
    for item in channels.values():
        regs = len(item["registrations"])
        clicks = int(item["clicks"] or 0)
        orders = int(item["orders"] or 0)
        channel_items.append({
            "aff_code": item["aff_code"],
            "utm_source": item["utm_source"],
            "utm_medium": item["utm_medium"],
            "utm_campaign": item["utm_campaign"],
            "clicks": clicks,
            "registrations": regs,
            "orders": orders,
            "revenue": int(item["revenue"] or 0),
            "register_rate_bps": (regs * 10000 // clicks) if clicks else 0,
            "order_rate_bps": (orders * 10000 // clicks) if clicks else 0,
            "latest_click_at": item["latest_click_at"].isoformat() if item["latest_click_at"] else None,
        })
    channel_items.sort(key=lambda item: (item["revenue"], item["orders"], item["clicks"]), reverse=True)

    recent_clicks = []
    for click in click_rows[:recent_limit]:
        recent_clicks.append({
            "id": click.id,
            "aff_code": click.aff_code,
            "agent_id": click.agent_id,
            "landing_url": click.landing_url,
            "ip": click.ip,
            "referer": click.referer,
            "utm_source": click.utm_source,
            "utm_medium": click.utm_medium,
            "utm_campaign": click.utm_campaign,
            "utm_content": click.utm_content,
            "utm_term": click.utm_term,
            "registered_user_id": click.registered_user_id,
            "converted_at": click.converted_at.isoformat() if click.converted_at else None,
            "created_at": click.created_at.isoformat() if click.created_at else None,
        })

    return ApiResponse(data={
        "summary": {
            "clicks": int(total_clicks),
            "unique_ips": int(unique_ips),
            "registrations": int(registrations),
            "paid_orders": int(paid_orders),
            "revenue": int(revenue),
            "register_rate_bps": (int(registrations) * 10000 // int(total_clicks)) if total_clicks else 0,
            "order_rate_bps": (int(paid_orders) * 10000 // int(total_clicks)) if total_clicks else 0,
        },
        "channels": channel_items,
        "recent_clicks": recent_clicks,
    })
