from fastapi import APIRouter, Depends, Header, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_db, get_admin_user, require_any_permission, require_permission
from app.core.models.user import User
from app.plugins.pos_operations import services
from app.plugins.pos_operations.quick_buttons import get_quick_buttons, upsert_quick_buttons
from app.plugins.pos_operations.schemas import StaffUpsertIn, ResetPinIn, StaffOut, QuickButtonsSaveIn


async def _require_enabled(db: AsyncSession, tenant_id: int) -> None:
    from app.core.services.plugin_helper import require_plugin
    await require_plugin("pos_operations", db, tenant_id)

admin_router = APIRouter(prefix="/pos/operations/admin", tags=["POS Operations Admin"])
snapshot_router = APIRouter(prefix="/pos/operations/snapshot", tags=["POS Operations Snapshot"])


def _staff_out(staff, pin: str | None = None) -> StaffOut:
    return StaffOut(user_id=staff.user_id, pos_enabled=bool(staff.pos_enabled),
                    store_ids=staff.store_ids or [], credential_version=staff.credential_version,
                    pin=pin)


@admin_router.post("/staff", response_model=StaffOut,
                   dependencies=[Depends(require_permission("pos.staff.manage"))])
async def upsert_staff_endpoint(body: StaffUpsertIn, db: AsyncSession = Depends(get_db),
                                current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    try:
        staff, generated_pin = await services.upsert_staff(
            db, tenant_id=current_user.tenant_id, user_id=body.user_id,
            pos_enabled=body.pos_enabled, store_ids=body.store_ids, pin=body.pin)
    except services.StaffInvalid as e:
        raise HTTPException(status_code=422, detail=str(e))
    return _staff_out(staff, pin=generated_pin)


@admin_router.post("/staff/reset-pin", response_model=StaffOut,
                   dependencies=[Depends(require_permission("pos.staff.manage"))])
async def reset_pin_endpoint(body: ResetPinIn, db: AsyncSession = Depends(get_db),
                             current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    staff, pin_value = await services.reset_pin(db, tenant_id=current_user.tenant_id, user_id=body.user_id, pin=body.pin)
    return _staff_out(staff, pin=pin_value)


@admin_router.get("/staff", response_model=list[StaffOut],
                  dependencies=[Depends(require_permission("pos.staff.manage"))])
async def list_staff_endpoint(db: AsyncSession = Depends(get_db),
                              current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    return [_staff_out(s) for s in await services.list_staff(db, current_user.tenant_id)]


# 门店下拉的数据源。三个 POS 页面都要用，所以接受其中任一权限。
@admin_router.get("/stores", dependencies=[Depends(require_any_permission(
    ["pos.staff.manage", "pos.rules.manage", "pos.audit.view"]))])
async def list_stores_endpoint(db: AsyncSession = Depends(get_db),
                               current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    return await services.list_stores(db, current_user.tenant_id)


# 收银员下拉的数据源。用 pos.staff.manage 而不是 permissions.users.view——
# 只管 POS 的管理员未必有查看后台用户列表的权限，那会让下拉变成空的。
@admin_router.get("/assignable-users",
                  dependencies=[Depends(require_permission("pos.staff.manage"))])
async def list_assignable_users_endpoint(db: AsyncSession = Depends(get_db),
                                         current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    return await services.list_assignable_users(db, current_user.tenant_id)


@admin_router.get("/rules", dependencies=[Depends(require_permission("pos.rules.manage"))])
async def get_rules_endpoint(store_id: int, db: AsyncSession = Depends(get_db),
                             current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    r = await services.get_rules(db, tenant_id=current_user.tenant_id, store_id=store_id)
    return {c.name: getattr(r, c.name) for c in r.__table__.columns if c.name not in ("id",)}


@admin_router.put("/rules", dependencies=[Depends(require_permission("pos.rules.manage"))])
async def put_rules_endpoint(store_id: int, data: dict, db: AsyncSession = Depends(get_db),
                             current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    try:
        r = await services.upsert_rules(db, tenant_id=current_user.tenant_id, store_id=store_id,
                                        data=data, actor_id=current_user.id)
    except services.RulesInvalid as e:
        raise HTTPException(status_code=422, detail=str(e))
    return {"ok": True, "rules_version": r.rules_version}


@admin_router.get("/quick-buttons", dependencies=[Depends(require_permission("pos.rules.manage"))])
async def get_quick_buttons_endpoint(store_id: int, db: AsyncSession = Depends(get_db),
                                     current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    return await get_quick_buttons(db, current_user.tenant_id, store_id)


@admin_router.put("/quick-buttons", dependencies=[Depends(require_permission("pos.rules.manage"))])
async def put_quick_buttons_endpoint(body: QuickButtonsSaveIn, db: AsyncSession = Depends(get_db),
                                     current_user: User = Depends(get_admin_user)):
    await _require_enabled(db, current_user.tenant_id)
    return await upsert_quick_buttons(
        db, current_user.tenant_id, body.store_id, [b.model_dump() for b in body.buttons])


# Staff snapshot for the Agent — authenticated by the lane sync token.
@snapshot_router.get("/staff")
async def staff_snapshot_endpoint(authorization: str | None = Header(default=None),
                                  db: AsyncSession = Depends(get_db)):
    from app.plugins.pos_sync.services import authenticate_lane_by_token
    if not authorization or not authorization.lower().startswith("bearer "):
        raise HTTPException(status_code=401, detail="missing POS sync token")
    lane = await authenticate_lane_by_token(db, authorization.split(" ", 1)[1].strip())
    # 这个端点会下发 PIN 哈希；插件关闭时必须拒绝，否则「关掉」只是界面上的开关。
    await _require_enabled(db, lane.tenant_id)
    return await services.build_staff_snapshot(db, tenant_id=lane.tenant_id)


@snapshot_router.get("/receipt-template")
async def receipt_template_snapshot_endpoint(authorization: str | None = Header(default=None),
                                             db: AsyncSession = Depends(get_db)):
    """向 Agent 下发受信小票模板 + 版本（内容 hash）+ 纸宽。

    Agent 只用此缓存渲染快照，不接收渲染进程传来的 HTML。template_version 用内容
    hash，管理员改模板即变，Agent 检测到变化才更新缓存。
    """
    from app.plugins.pos_sync.services import authenticate_lane_by_token
    if not authorization or not authorization.lower().startswith("bearer "):
        raise HTTPException(status_code=401, detail="missing POS sync token")
    lane = await authenticate_lane_by_token(db, authorization.split(" ", 1)[1].strip())
    await _require_enabled(db, lane.tenant_id)
    return await services.build_receipt_template_snapshot(
        db, tenant_id=lane.tenant_id, store_id=lane.store_id)


@snapshot_router.get("/quick-buttons")
async def snapshot_quick_buttons(authorization: str | None = Header(default=None),
                                 db: AsyncSession = Depends(get_db)):
    # 复用 services.lane_from_token（原在 returns_router.py 里叫 _lane_from_token）：
    # 它已经做了插件开关检查，这里不用再调 _require_enabled，否则就是查两遍。
    lane = await services.lane_from_token(db, authorization)
    return await get_quick_buttons(db, lane.tenant_id, lane.store_id)
