import { ApiV1Error } from "@/lib/api-v1/errors";

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

export async function parseJsonObject(request: Request) {
  const body = (await request.json().catch(() => null)) as unknown;
  if (!isRecord(body)) {
    throw new ApiV1Error(400, "invalid_json_body", "O corpo da requisicao deve ser um objeto JSON.");
  }
  return body;
}

export function optionalTrimmedString(value: unknown) {
  return typeof value === "string" ? value.trim() : "";
}

export function requireTrimmedString(value: unknown, code: string, message: string) {
  const normalized = optionalTrimmedString(value);
  if (!normalized) {
    throw new ApiV1Error(400, code, message);
  }
  return normalized;
}

export function optionalBoolean(value: unknown, fallback = false) {
  if (typeof value === "boolean") return value;
  if (typeof value === "string") {
    const normalized = value.trim().toLowerCase();
    if (normalized === "true") return true;
    if (normalized === "false") return false;
  }
  return fallback;
}

export function optionalNumber(value: unknown, fallback = 0) {
  const numeric = Number(value);
  if (!Number.isFinite(numeric)) return fallback;
  return numeric;
}

export function ensureArray(value: unknown, code: string, message: string) {
  if (!Array.isArray(value)) {
    throw new ApiV1Error(400, code, message);
  }
  return value;
}

export function ensureUuid(value: unknown, code: string, message: string) {
  const normalized = optionalTrimmedString(value);
  const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalized);
  if (!isUuid) {
    throw new ApiV1Error(400, code, message);
  }
  return normalized;
}

export function optionalUuid(value: unknown) {
  const normalized = optionalTrimmedString(value);
  if (!normalized) return "";
  return ensureUuid(normalized, "invalid_uuid", "Identificador invalido.");
}

export function parsePositiveIntQuery(value: string | null, fallback: number, code: string, message: string) {
  if (!value) return fallback;
  const parsed = Number(value);
  if (!Number.isFinite(parsed) || parsed <= 0) {
    throw new ApiV1Error(400, code, message);
  }
  return Math.floor(parsed);
}

export function ensureEnum<T extends readonly string[]>(
  value: unknown,
  allowed: T,
  code: string,
  message: string,
  fallback?: T[number]
) {
  const normalized = optionalTrimmedString(value);
  if (!normalized && fallback) return fallback;
  if (!allowed.includes(normalized as T[number])) {
    throw new ApiV1Error(400, code, message);
  }
  return normalized as T[number];
}

export function ensureObject(value: unknown, code: string, message: string) {
  if (!isRecord(value)) {
    throw new ApiV1Error(400, code, message);
  }
  return value;
}

export function ensurePhoneDigits(value: unknown, code: string, message: string) {
  const normalized = optionalTrimmedString(value).replace(/\D/g, "");
  if (!normalized) {
    throw new ApiV1Error(400, code, message);
  }

  let resolved = normalized;
  if (!resolved.startsWith("55") && (resolved.length === 10 || resolved.length === 11)) {
    resolved = `55${resolved}`;
  }

  if (resolved.length < 10 || resolved.length > 15) {
    throw new ApiV1Error(400, code, message);
  }

  return resolved;
}
