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

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

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

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

    // Generate new CSRF token
    const tokenData = this.csrfService.generateToken(undefined, sessionId, userId);

    // Set CSRF secret in secure cookie
    res.cookie("csrf-secret", tokenData.secret, {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "strict",
      maxAge: 3600000, // 1 hour
      path: "/",
    });

    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 = req.user?.sessionId || this.extractSessionId(req) || undefined;
    const userId = req.user?.id || "anonymous"; // Default for unauthenticated users

    // Invalidate existing tokens for this user
    this.csrfService.invalidateUserTokens(userId);

    // Generate new CSRF token
    const tokenData = this.csrfService.generateToken(undefined, sessionId, userId);

    // Set CSRF secret in secure cookie
    res.cookie("csrf-secret", tokenData.secret, {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "strict",
      maxAge: 3600000, // 1 hour
      path: "/",
    });

    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 || "anonymous";

    // Only allow admin users to see stats (you might want to add role checking)
    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;
  }
}
