import {
  Body,
  Controller,
  Get,
  HttpCode,
  HttpStatus,
  Post,
  Query,
  Req,
  UseGuards,
} from '@nestjs/common';
import {
  ApiBearerAuth,
  ApiOkResponse,
  ApiOperation,
  ApiTags,
} from '@nestjs/swagger';
import { JwtGuard } from '../../common/jwt.guard';
import { OptionalJwtGuard } from './optional-jwt.guard';
import {
  CompleteVerificationResultDto,
  StartVerificationDto,
  VerifaydaCallbackDto,
  VerificationStatusDto,
} from './verifayda.dto';
import { VerifaydaService } from './verifayda.service';

/** Shape the JWT strategy puts on `request.user` (see common/jwt.strategy.ts). */
interface AuthedUser {
  userId: string;
  email?: string;
  role?: string;
  passengerId?: string;
}

/** Minimal slices of the Express req we touch (avoids a hard dependency on
 * `@types/express`, which isn't resolved in this package). */
interface RequestWithOptionalUser {
  user?: AuthedUser;
}
interface RequestWithUser {
  user: AuthedUser;
}

@ApiTags('Fayda Verification')
@Controller('fayda/verification')
export class VerifaydaController {
  constructor(private readonly service: VerifaydaService) {}

  @Post('start')
  @HttpCode(HttpStatus.OK)
  @UseGuards(OptionalJwtGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiOperation({
    summary: 'Start a VeriFayda 2.0 verification session',
    description: `Creates a verification session and returns the eSignet authorize URL the frontend should send the user to.

- Works for **logged-in users** and **guests**. If a valid bearer token is present, the verification is tied to that user; when \`saveToAccount\` is true their account is marked verified on success.
- For a **PURCHASE** flow, pass \`bookingId\` to stamp the booking's seats as Fayda-verified.
- The returned \`authorizationUrl\` already carries the PKCE \`code_challenge\`, CSRF \`state\`, requested \`claims\`, and \`code_challenge_method=S256\`. The frontend simply navigates to it (full page or popup).`,
  })
  @ApiOkResponse({
    description: 'Authorize URL the frontend should redirect the user to.',
    schema: {
      example: {
        authorizationUrl:
          'https://esignet.example.com/authorize?client_id=...&state=...&code_challenge=...',
      },
    },
  })
  async start(
    @Body() dto: StartVerificationDto,
    @Req() req: RequestWithOptionalUser,
  ): Promise<{ authorizationUrl: string }> {
    const authorizationUrl = await this.service.startVerification({
      purpose: dto.purpose ?? 'PURCHASE',
      platform: dto.platform ?? 'WEB',
      userId: req.user?.userId,
      bookingId: dto.bookingId,
      saveToAccount: dto.saveToAccount,
    });
    return { authorizationUrl };
  }

  @Get('complete')
  @ApiOperation({
    summary: 'Complete a verification (Fayda redirect / client callback lands here)',
    description: `This is the registered Fayda \`redirect_uri\`. Fayda redirects the browser here with \`?code&state\``,
  })
  @ApiOkResponse({ type: CompleteVerificationResultDto })
  async complete(
    @Query() dto: VerifaydaCallbackDto,
  ): Promise<CompleteVerificationResultDto> {
    return this.service.completeVerification(dto);
  }

  @Get('status')
  @UseGuards(JwtGuard)
  @ApiBearerAuth('JWT-auth')
  @ApiOperation({
    summary: "Get the current user's Fayda verification status",
    description:
      'Returns whether the authenticated user has linked a verified Fayda identity to their account, when, and the name on file.',
  })
  @ApiOkResponse({ type: VerificationStatusDto })
  async status(
    @Req() req: RequestWithUser,
  ): Promise<VerificationStatusDto> {
    return this.service.getVerificationStatus(req.user.userId);
  }
}
