import { BadRequestException, Body, Controller, Get, Inject, Post, Query, Res, UnauthorizedException } from '@nestjs/common';
import type { Response } from 'express';
import { AuthService } from './AuthService';
import { AuthSessionDTO, ForgotPasswordDTO, LoginParamsDTO, ResetPasswordDTO, SignupParamsDTO, SignupSponsorParamsDTO } from './dtos/AuthDto';
import type { CommandResultDTO } from './presenters/CommandResultPresenter';
import { Public } from './Public';

@Public()
@Controller('auth')
export class AuthController {
  constructor(@Inject(AuthService) private readonly authService: AuthService) {}

  @Post('signup')
  async signup(@Body() params: SignupParamsDTO): Promise<AuthSessionDTO> {
    try {
      return await this.authService.signupWithEmail(params);
    } catch (error) {
      if (error instanceof Error) {
        // Convert validation or business logic errors to BadRequest
        throw new BadRequestException(error.message);
      }
      throw error;
    }
  }

  @Post('signup-sponsor')
  async signupSponsor(@Body() params: SignupSponsorParamsDTO): Promise<AuthSessionDTO> {
    return this.authService.signupSponsor(params);
  }

  @Post('login')
  async login(@Body() params: LoginParamsDTO): Promise<AuthSessionDTO> {
    try {
      return await this.authService.loginWithEmail(params);
    } catch (error) {
      if (error instanceof Error) {
        // Convert authentication errors to Unauthorized
        throw new UnauthorizedException(error.message);
      }
      throw error;
    }
  }

  @Get('session')
  async getSession(@Res() res: Response): Promise<void> {
    const session = await this.authService.getCurrentSession();
    // Nest treats `null`/`undefined` as "no body" for Express responses; we need JSON `null`
    // so browser clients can safely call `response.json()`.
    res.json(session);
  }

  @Post('logout')
  async logout(): Promise<CommandResultDTO> {
    return this.authService.logout();
  }

  @Get('iracing/start')
  async startIracingAuth(@Query('returnTo') returnTo?: string): Promise<{ redirectUrl: string }> {
    const redirectUrl = await this.authService.startIracingAuth(returnTo);
    return { redirectUrl };
  }

  @Get('iracing/callback')
  async iracingCallback(
    @Query('code') code: string,
    @Query('state') state: string,
    @Query('returnTo') returnTo?: string,
  ): Promise<AuthSessionDTO> {
    return this.authService.iracingCallback(code, state, returnTo);
  }

  @Post('forgot-password')
  async forgotPassword(@Body() params: ForgotPasswordDTO): Promise<{ message: string; magicLink?: string }> {
    return this.authService.forgotPassword(params);
  }

  @Post('reset-password')
  async resetPassword(@Body() params: ResetPasswordDTO): Promise<{ message: string }> {
    return this.authService.resetPassword(params);
  }
}