import type { ZodType, z } from "zod";
import { HttpError } from "./errors";

/**
 * Parses and validates multipart/form-data with a Zod schema.
 * Handles both string values and files.
 */
export async function parseFormData<TSchema extends ZodType>(
  request: Request,
  schema: TSchema,
): Promise<z.infer<TSchema>> {
  const contentType = request.headers.get("content-type") || "";
  
  if (!contentType.includes("multipart/form-data")) {
    throw new HttpError("Expected multipart/form-data", {
      status: 400,
      code: "INVALID_CONTENT_TYPE",
    });
  }

  const formData = await request.formData();
  const data: Record<string, unknown> = {};

  // Convert FormData entries to a plain object
  for (const [key, value] of formData.entries()) {
    if (value instanceof File) {
      // For files, store the File object
      data[key] = value;
    } else {
      // For strings, handle array values (e.g., "galleryImages[]")
      if (key.endsWith("[]")) {
        const arrayKey = key.slice(0, -2);
        if (!Array.isArray(data[arrayKey])) {
          data[arrayKey] = [];
        }
        (data[arrayKey] as unknown[]).push(value);
      } else {
        // Handle multiple values with the same key
        if (data[key] !== undefined) {
          // Convert to array if multiple values
          if (!Array.isArray(data[key])) {
            data[key] = [data[key]];
          }
          (data[key] as unknown[]).push(value);
        } else {
          data[key] = value;
        }
      }
    }
  }

  try {
    return schema.parse(data);
  } catch (error) {
    throw new HttpError("Invalid form data", {
      status: 400,
      code: "VALIDATION_ERROR",
      details: error,
    });
  }
}

/**
 * Helper to extract a specific field from FormData as a string.
 */
export function getFormDataString(formData: FormData, key: string): string {
  const value = formData.get(key);
  return value instanceof File ? "" : String(value ?? "");
}

/**
 * Helper to extract a specific field from FormData as a number.
 */
export function getFormDataNumber(formData: FormData, key: string): number | undefined {
  const value = formData.get(key);
  if (value === null || value instanceof File) return undefined;
  const num = Number(value);
  return isNaN(num) ? undefined : num;
}

/**
 * Helper to extract a specific field from FormData as a boolean.
 */
export function getFormDataBoolean(formData: FormData, key: string): boolean {
  const value = formData.get(key);
  return value === "true" || value === "1";
}

/**
 * Helper to extract all values for a key as an array.
 */
export function getFormDataArray(formData: FormData, key: string): string[] {
  return formData.getAll(key).filter((v): v is string => typeof v === "string");
}

/**
 * Helper to extract a File from FormData.
 */
export function getFormDataFile(formData: FormData, key: string): File | null {
  const value = formData.get(key);
  return value instanceof File ? value : null;
}

