import { Body, Controller, Get, Post, Req } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Throttle } from '@nestjs/throttler';
import type { Request } from 'express';
import { CurrentUser } from '../common/decorators/current-user.decorator';
import { Public } from '../common/decorators/public.decorator';
import type { JwtUserPayload } from './jwt.types';
import { UsersService } from '../users/users.service';
import { AuthService } from './auth.service';
import { LoginDto } from './dto/login.dto';
import { RefreshTokenDto } from './dto/refresh-token.dto';
import { LogoutDto } from './dto/logout.dto';
import { ForgotPasswordDto } from './dto/forgot-password.dto';
import { ResetPasswordDto } from './dto/reset-password.dto';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { resolveJwtAccessSecret } from '../config/runtime-config';

@ApiTags('auth')
@Controller('auth')
export class AuthController {
  constructor(
    private readonly auth: AuthService,
    private readonly users: UsersService,
    private readonly jwt: JwtService,
    private readonly config: ConfigService,
  ) {}

  @Get('me')
  @ApiBearerAuth('access-token')
  async me(@CurrentUser() user: JwtUserPayload) {
    const doc = await this.users.findByUid(user.uid);
    if (!doc) return null;
    return this.users.toClientUserWithManager(doc);
  }

  @Public()
  @Throttle({ default: { limit: 40, ttl: 60000 } })
  @Post('login')
  login(@Body() body: LoginDto) {
    return this.auth.login(body);
  }

  @Public()
  @Post('refresh')
  refresh(@Body() body: RefreshTokenDto) {
    return this.auth.refresh(body.refreshToken, body.deviceId);
  }

  @Public()
  @Post('logout')
  logout(@Body() body: LogoutDto, @Req() req: Request) {
    const refreshToken = body.refreshToken ?? body.refresh_token;
    let userId: string | undefined;

    const authHeader = req.headers.authorization;
    if (typeof authHeader === 'string' && authHeader.startsWith('Bearer ')) {
      try {
        const payload = this.jwt.verify<JwtUserPayload>(
          authHeader.slice(7).trim(),
          { secret: resolveJwtAccessSecret(this.config) },
        );
        userId = payload.sub;
      } catch {
        // Expired access token is fine for logout — refreshToken may still be sent.
      }
    }

    return this.auth.logout({ refreshToken, userId });
  }

  @Public()
  @Throttle({ default: { limit: 10, ttl: 60000 } })
  @Post('forgot-password')
  forgot(@Body() body: ForgotPasswordDto) {
    return this.auth.forgotPassword(body.email);
  }

  @Public()
  @Post('reset-password')
  reset(@Body() body: ResetPasswordDto) {
    return this.auth.resetPassword(body.token, body.newPassword);
  }
}
