import { Controller, Get, Post, Body, UseGuards, HttpCode, HttpStatus, Request, Res } from '@nestjs/common';
import type { Response } from 'express';
import { AuthService } from './auth.service';
import {
  CreateUserDto,
  LoginDto,
  RegisterDeviceDto,
  LogoutDeviceDto,
  ForgotPasswordDto,
  ResetPasswordDto,
  VerifyEmailDto,
  SocialLoginDto,
} from './auth.dto';
import { AuthGuard } from './auth.guard';
import { OptionalAuthGuard } from './optional-auth.guard';
import { DeviceService } from '../devices/device.service';

function requestContext(req: any) {
  return { ip: req.ip, userAgent: req.get?.('user-agent') || null };
}

@Controller('auth')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    private readonly deviceService: DeviceService,
  ) {}

  @Post('register')
  register(@Request() req, @Body() payload: CreateUserDto) {
    return this.authService.register(payload, requestContext(req));
  }

  @Post('login')
  @HttpCode(HttpStatus.OK)
  login(@Body() payload: LoginDto) {
    return this.authService.login(payload);
  }

  // Status varies by outcome: 200 for an existing/linked account, 201 for a newly created social signup.
  @Post('social')
  async socialLogin(
    @Request() req,
    @Res({ passthrough: true }) res: Response,
    @Body() payload: SocialLoginDto,
  ) {
    const result = await this.authService.socialLogin(payload, requestContext(req));
    res.status(result.statusCode);
    return result;
  }

  @Get('me')
  @UseGuards(AuthGuard)
  getCurrentUser(@Request() req) {
    return this.authService.getCurrentUser(req.user.id);
  }

  @Post('verify-email/request-otp')
  @UseGuards(AuthGuard)
  @HttpCode(HttpStatus.OK)
  requestEmailVerificationOtp(@Request() req) {
    return this.authService.requestEmailVerificationOtp(req.user.id);
  }

  @Post('verify-email')
  @UseGuards(AuthGuard)
  @HttpCode(HttpStatus.OK)
  verifyEmail(@Request() req, @Body() payload: VerifyEmailDto) {
    return this.authService.verifyEmail(req.user.id, payload.otp);
  }

  @Post('forgot-password')
  @HttpCode(HttpStatus.OK)
  forgotPassword(@Body() payload: ForgotPasswordDto) {
    return this.authService.sendForgotPasswordOTP(payload.email);
  }

  @Post('reset-password')
  @HttpCode(HttpStatus.OK)
  resetPassword(@Body() payload: ResetPasswordDto) {
    return this.authService.resetPassword(payload);
  }

  // Express: no auth guard — device_id is required, user_id is optional (attached if logged in).
  // Status varies by outcome: 200 when updating an existing device row, 201 when creating one.
  @Post('devices/register')
  @UseGuards(OptionalAuthGuard)
  async registerDevice(
    @Request() req,
    @Res({ passthrough: true }) res: Response,
    @Body() data: RegisterDeviceDto,
  ) {
    const result = await this.deviceService.upsertDevice({ ...data, user_id: req.user?.id });
    res.status(result.statusCode);
    return {
      status: result.status,
      statusCode: result.statusCode,
      data: {
        message: 'Device registered',
        device_id: result.data?.device_id,
        user_id: result.data?.user_id ?? null,
      },
    };
  }

  // Status varies by outcome: 200 when found and detached, 404 when the device doesn't exist.
  @Post('devices/logout')
  async logoutDevice(@Res({ passthrough: true }) res: Response, @Body() data: LogoutDeviceDto) {
    const result = await this.deviceService.detachDeviceUser(data.device_id);
    res.status(result.statusCode);
    return result;
  }
}
