import { Controller, Get, Post, Req, Res, Inject, ForbiddenException } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import type { Request, Response } from "express";
import { Logger } from "nestjs-pino";
import { CsrfService } from "../services/csrf.service.js";
import { Public } from "@bff/modules/auth/decorators/public.decorator.js";
import type { UserAuth } from "@customer-portal/domain/customer";

export type AuthenticatedRequest = Request & {
  user?: UserAuth;
  sessionID?: string;
};

@Controller("security/csrf")
export class CsrfController {
  constructor(
    private readonly csrfService: CsrfService,
    private readonly configService: ConfigService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  @Public()
  @Get("token")
  getCsrfToken(@Req() req: AuthenticatedRequest, @Res() res: Response) {
    const sessionId = this.extractSessionId(req) || undefined;
    const userId = req.user?.id;

    // Generate new CSRF token
    const tokenData = this.csrfService.generateToken(undefined, sessionId, userId);
    const isProduction = this.configService.get("NODE_ENV") === "production";
    const cookieName = this.csrfService.getCookieName();

    // Set CSRF secret in secure cookie
    res.cookie(cookieName, tokenData.secret, {
      httpOnly: true,
      secure: isProduction,
      sameSite: "strict",
      maxAge: this.csrfService.getTokenTtl(),
      path: "/api",
    });

    this.logger.debug("CSRF token requested", {
      userId,
      sessionId,
      userAgent: req.get("user-agent"),
      ip: req.ip,
    });

    return res.json({
      success: true,
      token: tokenData.token,
      expiresAt: tokenData.expiresAt.toISOString(),
    });
  }

  @Public()
  @Post("refresh")
  refreshCsrfToken(@Req() req: AuthenticatedRequest, @Res() res: Response) {
    const sessionId = this.extractSessionId(req) || undefined;
    const userId = req.user?.id;

    // Generate new CSRF token
    const tokenData = this.csrfService.generateToken(undefined, sessionId, userId);
    const isProduction = this.configService.get("NODE_ENV") === "production";
    const cookieName = this.csrfService.getCookieName();

    // Set CSRF secret in secure cookie
    res.cookie(cookieName, tokenData.secret, {
      httpOnly: true,
      secure: isProduction,
      sameSite: "strict",
      maxAge: this.csrfService.getTokenTtl(),
      path: "/api",
    });

    this.logger.debug("CSRF token refreshed", {
      userId,
      sessionId,
      userAgent: req.get("user-agent"),
      ip: req.ip,
    });

    return res.json({
      success: true,
      token: tokenData.token,
      expiresAt: tokenData.expiresAt.toISOString(),
    });
  }

  @Get("stats")
  getCsrfStats(@Req() req: AuthenticatedRequest) {
    const userId = req.user?.id;
    const role = req.user?.role;
    if (role !== "ADMIN") {
      throw new ForbiddenException("Admin access required");
    }

    this.logger.debug("CSRF stats requested", {
      userId,
      userAgent: req.get("user-agent"),
      ip: req.ip,
    });

    const stats = this.csrfService.getTokenStats();

    return {
      success: true,
      stats,
    };
  }

  private extractSessionId(req: AuthenticatedRequest): string | null {
    const cookies = req.cookies as Record<string, string | undefined> | undefined;
    const sessionCookie = cookies?.["session-id"] ?? cookies?.["connect.sid"];
    return sessionCookie ?? req.sessionID ?? null;
  }
}
