import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  Request,
  BadRequestException,
} from '@nestjs/common';
import type { Request as ExpressRequest } from 'express';
import { Public } from '@common/decorators/public.decorator';
import { RequirePermissions } from '@common/decorators/permissions.decorator';
import { SharedCheckinService } from '../services/shared-checkin.service';
import {
  CreatePartnerDto,
  UpdatePartnerDto,
  DispatchRequestDto,
  ValidateTicketRequestDto,
} from '../dto/shared-checkin.dto';
import { isAllowedHost } from '../utils/shared-checkin.util';
import { SiteAttendanceErrorCodes } from '../error-codes';

@Controller('site-attendance')
export class SharedCheckinController {
  constructor(private readonly sharedCheckinService: SharedCheckinService) {}

  // --- Public QR token endpoint ---

  @Get('checkpoints/code/:code/qr-token')
  @Public()
  async getQrToken(@Param('code') code: string) {
    return this.sharedCheckinService.getQrTokenForCheckpoint(code);
  }

  @Get('checkpoints/code/:code/dispatch-options')
  @Public()
  async getDispatchOptions(
    @Param('code') code: string,
    @Query('t') qrToken: string,
  ) {
    return this.sharedCheckinService.getDispatchOptions(code, qrToken);
  }

  // --- Dispatch / ticket ---

  @Post('shared-checkin/dispatch')
  @Public()
  async dispatch(
    @Body() dto: DispatchRequestDto,
    @Request() req: ExpressRequest,
  ) {
    // Compute dispatchOrigin from request (Referer or x-forwarded-host+proto)
    const referer = (req.headers['referer'] as string | undefined) ?? '';
    if (!referer || !isAllowedHost(referer)) {
      throw new BadRequestException({
        code: SiteAttendanceErrorCodes.TICKET_ORIGIN_NOT_ALLOWED,
        message:
          'Request must come from an allowed dispatch origin (configure SHARED_CHECKIN_ALLOWED_HOSTS)',
      });
    }
    // Normalize dispatchOrigin to the exact URL path where the dispatch page runs
    const url = new URL(referer);
    const dispatchOrigin = `${url.protocol}//${url.host}${url.pathname}`;
    return this.sharedCheckinService.dispatch(dto, dispatchOrigin);
  }

  @Post('shared-checkin/validate-ticket')
  @Public()
  async validateTicket(@Body() dto: ValidateTicketRequestDto) {
    return this.sharedCheckinService.validateTicket(
      dto.ticket,
      dto.targetCheckpointCode,
    );
  }

  @Post('internal/shared-checkin/cleanup-ticket-usage')
  @Public()
  async cleanupTicketUsage() {
    // 内部 cron 调用；生产应加 IP 限制 / x-internal header 校验（v1.5 留作运维白名单）
    const result = await this.sharedCheckinService.cleanupTicketUsage();
    return { deletedCount: result.count };
  }

  // --- Partner CRUD ---

  @Get('checkpoints/:id/partners')
  @RequirePermissions('site-attendance:sharedCheckin:manage')
  async listPartners(@Param('id') id: string) {
    const partners = await this.sharedCheckinService.listPartners(id);
    return { partners };
  }

  @Post('checkpoints/:id/partners')
  @RequirePermissions('site-attendance:sharedCheckin:manage')
  async createPartner(
    @Param('id') id: string,
    @Body() dto: CreatePartnerDto,
    @Request() req: ExpressRequest,
  ) {
    const user = req.user as { userId?: string; id?: string } | undefined;
    const userId = user?.userId ?? user?.id;
    return this.sharedCheckinService.createPartner(id, dto, userId!);
  }

  @Patch('partners/:partnerId')
  @RequirePermissions('site-attendance:sharedCheckin:manage')
  async updatePartner(
    @Param('partnerId') partnerId: string,
    @Body() dto: UpdatePartnerDto,
    @Request() req: ExpressRequest,
  ) {
    const user = req.user as { userId?: string; id?: string } | undefined;
    const userId = user?.userId ?? user?.id;
    return this.sharedCheckinService.updatePartner(partnerId, dto, userId!);
  }

  @Delete('partners/:partnerId')
  @RequirePermissions('site-attendance:sharedCheckin:manage')
  async deletePartner(@Param('partnerId') partnerId: string) {
    await this.sharedCheckinService.deletePartner(partnerId);
    return; // 204
  }
}
