import { Controller, Post, Body, HttpCode, HttpStatus, BadRequestException } from '@nestjs/common';
import { z } from 'zod';
import { AuthService } from './auth.service';

/** Parse a Zod schema and throw a NestJS 400 instead of a raw ZodError */
function parseBody<T>(schema: z.ZodType<T>, body: unknown): T {
  const result = schema.safeParse(body);
  if (!result.success) {
    throw new BadRequestException(result.error.errors[0].message);
  }
  return result.data;
}

// ---------------------------------------------------------------------------
// Validation schemas
// ---------------------------------------------------------------------------

/** Password rules: min 8 chars, upper, lower, digit, special char */
const PasswordSchema = z
  .string()
  .min(8, 'Minimum 8 characters')
  .regex(/[A-Z]/, 'Must contain an uppercase letter')
  .regex(/[a-z]/, 'Must contain a lowercase letter')
  .regex(/[0-9]/, 'Must contain a digit')
  .regex(/[^A-Za-z0-9]/, 'Must contain a special character');

const RegisterSchema = z.object({
  email: z.string().email().max(255).toLowerCase(),
  password: PasswordSchema,
});

const VerifyEmailSchema = z.object({
  email: z.string().email(),
  code: z.string().length(6).regex(/^\d{6}$/),
});

const LoginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(1),
});

const ForgotPasswordSchema = z.object({
  email: z.string().email(),
});

const ResetPasswordSchema = z.object({
  email: z.string().email(),
  code: z.string().length(6).regex(/^\d{6}$/),
  newPassword: PasswordSchema,
});

const ResendOtpSchema = z.object({
  email: z.string().email(),
});

// ---------------------------------------------------------------------------
// Controller
// ---------------------------------------------------------------------------

/**
 * AuthController — all routes are public (no JWT guard).
 * Handles registration, email verification, login, and password reset.
 */
@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  /** POST /auth/register — create account, sends OTP by email */
  @Post('register')
  @HttpCode(HttpStatus.CREATED)
  async register(@Body() body: unknown): Promise<void> {
    const { email, password } = parseBody(RegisterSchema, body);
    return this.authService.register(email, password);
  }

  /** POST /auth/verify-email — confirm OTP, returns JWT */
  @Post('verify-email')
  @HttpCode(HttpStatus.OK)
  async verifyEmail(@Body() body: unknown): Promise<{ accessToken: string }> {
    const { email, code } = parseBody(VerifyEmailSchema, body);
    return this.authService.verifyEmail(email, code);
  }

  /** POST /auth/login — authenticate, returns JWT */
  @Post('login')
  @HttpCode(HttpStatus.OK)
  async login(@Body() body: unknown): Promise<{ accessToken: string }> {
    const { email, password } = parseBody(LoginSchema, body);
    return this.authService.login(email, password);
  }

  /** POST /auth/forgot-password — sends OTP reset code (always 200) */
  @Post('forgot-password')
  @HttpCode(HttpStatus.OK)
  async forgotPassword(@Body() body: unknown): Promise<void> {
    const { email } = parseBody(ForgotPasswordSchema, body);
    return this.authService.forgotPassword(email);
  }

  /** POST /auth/reset-password — validates OTP and sets new password */
  @Post('reset-password')
  @HttpCode(HttpStatus.OK)
  async resetPassword(@Body() body: unknown): Promise<void> {
    const { email, code, newPassword } = parseBody(ResetPasswordSchema, body);
    return this.authService.resetPassword(email, code, newPassword);
  }

  /** POST /auth/resend-otp — resend email verification code */
  @Post('resend-otp')
  @HttpCode(HttpStatus.OK)
  async resendOtp(@Body() body: unknown): Promise<void> {
    const { email } = parseBody(ResendOtpSchema, body);
    return this.authService.resendOtp(email);
  }
}
