import { Controller, All, Req, Get, UseGuards, Request, Logger } from "@nestjs/common";
import { Throttle } from "@nestjs/throttler";
import type { AuthUser, AuthSession } from "@mosaic/shared";
import { AuthService } from "./auth.service";
import { AuthGuard } from "./guards/auth.guard";
import { CurrentUser } from "./decorators/current-user.decorator";

interface RequestWithSession {
  user?: AuthUser;
  session?: {
    id: string;
    token: string;
    expiresAt: Date;
    [key: string]: unknown;
  };
}

@Controller("auth")
export class AuthController {
  private readonly logger = new Logger(AuthController.name);

  constructor(private readonly authService: AuthService) {}

  /**
   * Get current session
   * Returns user and session data for authenticated user
   */
  @Get("session")
  @UseGuards(AuthGuard)
  getSession(@Request() req: RequestWithSession): AuthSession {
    if (!req.user || !req.session) {
      // This should never happen after AuthGuard, but TypeScript needs the check
      throw new Error("User session not found");
    }

    return {
      user: req.user,
      session: {
        id: req.session.id,
        token: req.session.token,
        expiresAt: req.session.expiresAt,
      },
    };
  }

  /**
   * Get current user profile
   * Returns basic user information
   */
  @Get("profile")
  @UseGuards(AuthGuard)
  getProfile(@CurrentUser() user: AuthUser): AuthUser {
    // Return only defined properties to maintain type safety
    const profile: AuthUser = {
      id: user.id,
      email: user.email,
      name: user.name,
    };

    if (user.image !== undefined) {
      profile.image = user.image;
    }
    if (user.emailVerified !== undefined) {
      profile.emailVerified = user.emailVerified;
    }
    if (user.workspaceId !== undefined) {
      profile.workspaceId = user.workspaceId;
    }
    if (user.currentWorkspaceId !== undefined) {
      profile.currentWorkspaceId = user.currentWorkspaceId;
    }
    if (user.workspaceRole !== undefined) {
      profile.workspaceRole = user.workspaceRole;
    }

    return profile;
  }

  /**
   * Handle all other auth routes (sign-in, sign-up, sign-out, etc.)
   * Delegates to BetterAuth
   *
   * Rate limit: "strict" tier (10 req/min) - More restrictive than normal routes
   * to prevent brute-force attacks on auth endpoints
   *
   * Security note: This catch-all route bypasses standard guards that other routes have.
   * Rate limiting and logging are applied to mitigate abuse (SEC-API-10).
   */
  @All("*")
  @Throttle({ strict: { limit: 10, ttl: 60000 } })
  async handleAuth(@Req() req: Request): Promise<unknown> {
    // Extract client IP for logging
    const clientIp = this.getClientIp(req);
    const requestPath = (req as unknown as { url?: string }).url ?? "unknown";
    const method = (req as unknown as { method?: string }).method ?? "UNKNOWN";

    // Log auth catch-all hits for monitoring and debugging
    this.logger.debug(`Auth catch-all: ${method} ${requestPath} from ${clientIp}`);

    const auth = this.authService.getAuth();
    return auth.handler(req);
  }

  /**
   * Extract client IP from request, handling proxies
   */
  private getClientIp(req: Request): string {
    const reqWithHeaders = req as unknown as {
      headers?: Record<string, string | string[] | undefined>;
      ip?: string;
      socket?: { remoteAddress?: string };
    };

    // Check X-Forwarded-For header (for reverse proxy setups)
    const forwardedFor = reqWithHeaders.headers?.["x-forwarded-for"];
    if (forwardedFor) {
      const ips = Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor;
      return ips?.split(",")[0]?.trim() ?? "unknown";
    }

    // Fall back to direct IP
    return reqWithHeaders.ip ?? reqWithHeaders.socket?.remoteAddress ?? "unknown";
  }
}
