import type { APIRoute } from "astro";
import { prisma } from "../lib/prisma";
import { Prisma } from "@prisma/client";

export const prerender = false;

const SORT_FIELDS = new Set([
  "numero_voluntario",
  "submitted_at",
  "nombre",
  "apellido",
  "correo",
  "status",
  "pais",
]);

const SEARCHABLE_FIELDS = [
  "nombre",
  "segundo_nombre",
  "apellido",
  "correo",
  "telefono",
  "whatsapp",
  "documento_nro",
  "ciudad",
  "profesion",
  "nivel_academico",
  "nacionalidad",
] as const;

const CORE_TEXT_FILTERS = ["documento_nro"] as const;

const FUZZY_TEXT_FILTERS = [
  "ciudad",
  "estado",
  "profesion",
  "nivel_academico",
] as const;

const FUZZY_THRESHOLD = 0.35;

const CORE_EXACT_FILTERS = [
  "sexo",
  "nacionalidad",
  "form_version",
] as const;

const RESPONSE_FILTERS = [
  "idioma",
  "areas_colaborar",
  "dias_disponibles",
  "horario_preferido",
  "fuera_ciudad",
  "misiones_internacionales",
  "condicion_medica",
  "voluntariado_anterior",
] as const;

function splitList(v: string): string[] {
  return v
    .split(",")
    .map((s) => s.trim())
    .filter(Boolean);
}

function tokenToOr(token: string): Prisma.FormularioWhereInput {
  const or: Prisma.FormularioWhereInput[] = SEARCHABLE_FIELDS.map((field) => ({
    [field]: { contains: token, mode: "insensitive" },
  }));
  or.push({
    respuestas: {
      some: { value: { contains: token, mode: "insensitive" } },
    },
  });
  if (/^\d+$/.test(token)) {
    or.push({ numero_voluntario: { equals: Number(token) } });
  }
  return { OR: or };
}

function buildSearchWhere(q: string): Prisma.FormularioWhereInput {
  const tokens = q.split(/\s+/).filter(Boolean);
  if (tokens.length === 1) return tokenToOr(tokens[0]);
  return { AND: tokens.map(tokenToOr) };
}

function buildDateRange(desde: string, hasta: string): Prisma.FormularioWhereInput | null {
  const filter: Prisma.DateTimeFilter = {};
  if (desde) filter.gte = new Date(desde);
  if (hasta) {
    const h = new Date(hasta);
    h.setHours(23, 59, 59, 999);
    filter.lte = h;
  }
  if (Object.keys(filter).length === 0) return null;
  return { submitted_at: filter };
}

function buildAgeRange(min: string, max: string): Prisma.FormularioWhereInput | null {
  const filter: Prisma.DateTimeFilter = {};
  const now = new Date();
  if (min) {
    const maxBirth = new Date(now);
    maxBirth.setFullYear(now.getFullYear() - Number(min));
    filter.lte = maxBirth;
  }
  if (max) {
    const minBirth = new Date(now);
    minBirth.setFullYear(now.getFullYear() - Number(max) - 1);
    minBirth.setDate(minBirth.getDate() + 1);
    filter.gte = minBirth;
  }
  if (Object.keys(filter).length === 0) return null;
  return { fecha_nacimiento: filter };
}

function buildResponseFilter(key: string, values: string[]): Prisma.FormularioWhereInput {
  const or: Prisma.FormularioWhereInput[] = values.map((v) => ({
    respuestas: {
      some: { key, value: { contains: v, mode: "insensitive" } },
    },
  }));
  return or.length === 1 ? or[0] : { OR: or };
}

async function fuzzyIds(field: string, value: string): Promise<string[]> {
  const col = Prisma.raw(field);
  const rows = await prisma.$queryRaw<{ id: string }[]>`
    SELECT id::text AS id
    FROM formularios
    WHERE ${col} IS NOT NULL
      AND ${col} <> ''
      AND length(${col}) >= 2
      AND (
        similarity(lower(${col}), lower(${value})) > ${FUZZY_THRESHOLD}
        OR ${col} ILIKE ${`%${value}%`}
      )
    LIMIT 5000
  `;
  return rows.map((r) => r.id);
}

export const GET: APIRoute = async ({ url }) => {
  try {
    const sp = url.searchParams;
    const page = Math.max(1, parseInt(sp.get("page") || "1", 10));
    const limit = Math.min(100, Math.max(1, parseInt(sp.get("limit") || "25", 10)));
    const q = (sp.get("q") || "").trim();
    const status = (sp.get("status") || "").trim();
    const pais = (sp.get("pais") || "").trim();
    const sort = SORT_FIELDS.has(sp.get("sort") || "") ? sp.get("sort")! : "submitted_at";
    const order = sp.get("order") === "asc" ? "asc" : "desc";

    const conditions: Prisma.FormularioWhereInput[] = [];

    if (q) conditions.push(buildSearchWhere(q));

    const dateRange = buildDateRange((sp.get("desde") || "").trim(), (sp.get("hasta") || "").trim());
    if (dateRange) conditions.push(dateRange);

    const ageRange = buildAgeRange((sp.get("edad_min") || "").trim(), (sp.get("edad_max") || "").trim());
    if (ageRange) conditions.push(ageRange);

    if (status) conditions.push({ status: { in: splitList(status) } });
    if (pais) conditions.push({ pais: { in: splitList(pais) } });

    for (const field of CORE_TEXT_FILTERS) {
      const v = (sp.get(field) || "").trim();
      if (v) conditions.push({ [field]: { contains: v, mode: "insensitive" } });
    }

    for (const field of FUZZY_TEXT_FILTERS) {
      const v = (sp.get(field) || "").trim();
      if (v) {
        const ids = await fuzzyIds(field, v);
        conditions.push(ids.length ? { id: { in: ids } } : { id: { in: [] } });
      }
    }

    for (const field of CORE_EXACT_FILTERS) {
      const v = (sp.get(field) || "").trim();
      if (v) conditions.push({ [field]: { in: splitList(v) } });
    }

    for (const key of RESPONSE_FILTERS) {
      const v = (sp.get(key) || "").trim();
      if (v) conditions.push(buildResponseFilter(key, splitList(v)));
    }

    const where: Prisma.FormularioWhereInput = conditions.length ? { AND: conditions } : {};

    const [total, rows] = await Promise.all([
      prisma.formulario.count({ where }),
      prisma.formulario.findMany({
        where,
        include: { respuestas: { select: { key: true, value: true } } },
        orderBy: { [sort]: order },
        skip: (page - 1) * limit,
        take: limit,
      }),
    ]);

    const data = rows.map((f) => {
      const respuestas: Record<string, string> = {};
      for (const r of f.respuestas) {
        respuestas[r.key] = respuestas[r.key]
          ? `${respuestas[r.key]}, ${r.value}`
          : r.value;
      }
      return {
        id: f.id,
        numero_voluntario: f.numero_voluntario,
        nombre_completo: [f.nombre, f.segundo_nombre, f.apellido]
          .filter(Boolean)
          .join(" "),
        nombre: f.nombre,
        segundo_nombre: f.segundo_nombre,
        apellido: f.apellido,
        correo: f.correo,
        telefono: f.telefono,
        whatsapp: f.whatsapp,
        pais: f.pais,
        ciudad: f.ciudad,
        estado: f.estado,
        profesion: f.profesion,
        nivel_academico: f.nivel_academico,
        status: f.status,
        submitted_at: f.submitted_at,
        ...respuestas,
      };
    });

    return Response.json({
      success: true,
      data,
      total,
      page,
      limit,
      totalPages: Math.ceil(total / limit),
    }, {
      headers: { "Cache-Control": "private, max-age=30, stale-while-revalidate=120" },
    });
  } catch (error) {
    console.error("Error en /api/admin/voluntarios:", error);
    return Response.json(
      { success: false, message: "Error al obtener voluntarios" },
      { status: 500 }
    );
  }
};
