import { Body, Controller, Get, Param, Post, Req, UseGuards } from "@nestjs/common";
import {
  ConfirmPasswordResetRequest,
  ConsumeMagicLinkRequest,
  EntityId,
  LoginRequest,
  RefreshRequest,
  RequestMagicLinkRequest,
  RequestPasswordResetRequest,
  SignupRequest,
  VerifyEmailRequest,
} from "@slackwsh/contracts";
import { AuthService, type RequestMeta } from "./auth.service";
import { AuthGuard } from "./auth.guard";
import { CurrentUser } from "./current-user.decorator";
import type { RequestUser } from "./auth.guard";

function metaFrom(req: any): RequestMeta {
  return {
    ip: req.ip,
    userAgent: req.headers?.["user-agent"],
  };
}

@Controller("auth")
export class AuthController {
  constructor(private readonly auth: AuthService) {}

  @Post("signup")
  async signup(@Body() body: unknown) {
    return this.auth.signup(SignupRequest.parse(body));
  }

  @Post("verify-email")
  async verifyEmail(@Body() body: unknown) {
    const { token } = VerifyEmailRequest.parse(body);
    await this.auth.verifyEmail(token);
    return { verified: true };
  }

  @Post("login")
  async login(@Body() body: unknown, @Req() req: any) {
    const input = LoginRequest.parse(body);
    return this.auth.login(input, { ...metaFrom(req), deviceLabel: input.deviceLabel });
  }

  @Post("refresh")
  async refresh(@Body() body: unknown, @Req() req: any) {
    const { refreshToken } = RefreshRequest.parse(body);
    return this.auth.refresh(refreshToken, metaFrom(req));
  }

  @Post("logout")
  async logout(@Body() body: unknown) {
    const { refreshToken } = RefreshRequest.parse(body);
    await this.auth.logout(refreshToken);
    return { loggedOut: true };
  }

  @Post("magic-link/request")
  async requestMagicLink(@Body() body: unknown) {
    const { email } = RequestMagicLinkRequest.parse(body);
    await this.auth.requestMagicLink(email);
    return { requested: true };
  }

  @Post("magic-link/consume")
  async consumeMagicLink(@Body() body: unknown, @Req() req: any) {
    const { token } = ConsumeMagicLinkRequest.parse(body);
    return this.auth.consumeMagicLink(token, metaFrom(req));
  }

  @Post("password-reset/request")
  async requestPasswordReset(@Body() body: unknown) {
    const { email } = RequestPasswordResetRequest.parse(body);
    await this.auth.requestPasswordReset(email);
    return { requested: true };
  }

  @Post("password-reset/confirm")
  async confirmPasswordReset(@Body() body: unknown) {
    const { token, newPassword } = ConfirmPasswordResetRequest.parse(body);
    await this.auth.confirmPasswordReset(token, newPassword);
    return { reset: true };
  }

  @UseGuards(AuthGuard)
  @Get("devices")
  async listDevices(@CurrentUser() user: RequestUser) {
    return { sessions: await this.auth.listDevices(user.userId) };
  }

  @UseGuards(AuthGuard)
  @Post("devices/:sessionId/revoke")
  async revokeDevice(@CurrentUser() user: RequestUser, @Param("sessionId") sessionId: string) {
    await this.auth.revokeSession(user.userId, EntityId.parse(sessionId));
    return { revoked: true };
  }
}
