import {
  Body,
  Controller,
  Get,
  HttpCode,
  HttpStatus,
  Post,
  Query,
  Req,
  UseGuards,
} from '@nestjs/common';
import {
  ApiBearerAuth,
  ApiOkResponse,
  ApiOperation,
  ApiTags,
} from '@nestjs/swagger';
import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type';
import { IsPublic } from '@tria-plc/api-common/modules/auth/decorators/public.decorator';
import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard';
import { OptionalJwtGuard } from './optional-jwt.guard';
import {
  CompleteVerificationResultDto,
  StartVerificationDto,
  VerifaydaCallbackDto,
  VerificationStatusDto,
} from './verifayda.dto';
import { VerifaydaService } from './verifayda.service';

/** 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?: TCurrentUser;
}
interface RequestWithUser {
  user: TCurrentUser;
}

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

  @Post('start')
  @IsPublic()
  @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.
- **VERIFY** (default): the user proves their identity and \`/complete\` returns the verified attributes (name, email, phone, dob, gender).
- **LOGIN**: \`/complete\` resolves/creates the user and returns a JWT.
- 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 ?? 'VERIFY',
      platform: dto.platform ?? 'WEB',
      userId: req.user?.id,
      wantsPasswordSetup: dto.wantsPasswordSetup ?? false,
    });
    return { authorizationUrl };
  }

  @Get('complete')
  @IsPublic()
  @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.id);
  }
}
