import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus, Inject } from "@nestjs/common";
import type { Request, Response } from "express";
import { Logger } from "nestjs-pino";
import { ZodValidationException } from "nestjs-zod";
import type { ZodError, ZodIssue } from "zod";

interface ZodIssueResponse {
  path: string;
  message: string;
  code: string;
}

@Catch(ZodValidationException)
export class ZodValidationExceptionFilter implements ExceptionFilter {
  constructor(@Inject(Logger) private readonly logger: Logger) {}

  catch(exception: ZodValidationException, host: ArgumentsHost): void {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    const rawZodError = exception.getZodError();
    let issues: ZodIssueResponse[] = [];

    if (!this.isZodError(rawZodError)) {
      this.logger.error("ZodValidationException did not contain a ZodError", {
        path: request.url,
        method: request.method,
        providedType: typeof rawZodError,
      });
    } else {
      issues = this.mapIssues(rawZodError.issues);
    }

    this.logger.warn("Request validation failed", {
      path: request.url,
      method: request.method,
      issues,
    });

    response.status(HttpStatus.BAD_REQUEST).json({
      success: false as const,
      error: {
        code: "VALIDATION_FAILED",
        message: "Request validation failed",
        details: {
          issues,
          timestamp: new Date().toISOString(),
          path: request.url,
        },
      },
    });
  }

  private isZodError(error: unknown): error is ZodError {
    return Boolean(
      error && typeof error === "object" && Array.isArray((error as { issues?: unknown }).issues)
    );
  }

  private mapIssues(issues: ZodIssue[]): ZodIssueResponse[] {
    return issues.map(issue => ({
      path: issue.path.join(".") || "root",
      message: issue.message,
      code: issue.code,
    }));
  }
}
