import type { APIRoute } from "astro";

export const prerender = false;

type ApiErrorCode =
  | "methodNotAllowed"
  | "invalidRequest"
  | "rateLimited"
  | "notConfigured"
  | "emailFailed";

type ApiErrorResponse = {
  ok: false;
  error: {
    code: ApiErrorCode;
    message: string;
  };
};

type ApiOkResponse = {
  ok: true;
};

const respondJson = (
  status: number,
  body: ApiOkResponse | ApiErrorResponse,
) => {
  return new Response(JSON.stringify(body), {
    status,
    headers: {
      "content-type": "application/json; charset=utf-8",
      "cache-control": "no-store",
    },
  });
};

const getClientIp = (request: Request, fallbackIp: string) => {
  const xff = request.headers.get("x-forwarded-for");
  if (xff) return xff.split(",")[0]?.trim() || fallbackIp;
  const xri = request.headers.get("x-real-ip");
  if (xri) return xri.trim();
  return fallbackIp;
};

type RateLimitEntry = {
  windowStartMs: number;
  count: number;
};

const rateLimitWindowMs = 60_000;
const rateLimitMax = 5;
const rateLimitMap = new Map<string, RateLimitEntry>();

const isRateLimited = (key: string, nowMs: number) => {
  const existing = rateLimitMap.get(key);
  if (!existing) {
    rateLimitMap.set(key, { windowStartMs: nowMs, count: 1 });
    return false;
  }

  if (nowMs - existing.windowStartMs > rateLimitWindowMs) {
    rateLimitMap.set(key, { windowStartMs: nowMs, count: 1 });
    return false;
  }

  existing.count += 1;
  rateLimitMap.set(key, existing);
  return existing.count > rateLimitMax;
};

const normalizeText = (value: string, maxLen: number) => {
  const collapsed = value.replace(/[\u0000-\u001F\u007F]/g, " ").trim();
  if (collapsed.length <= maxLen) return collapsed;
  return collapsed.slice(0, maxLen);
};

const isEmailLike = (value: string) => {
  const v = value.trim();
  if (v.length < 6 || v.length > 254) return false;
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
};

const readBody = async (request: Request) => {
  const contentType = request.headers.get("content-type") ?? "";

  if (
    contentType.includes("application/x-www-form-urlencoded") ||
    contentType.includes("multipart/form-data")
  ) {
    const data = await request.formData();
    return {
      name: String(data.get("name") ?? ""),
      email: String(data.get("email") ?? ""),
      subject: String(data.get("subject") ?? ""),
      message: String(data.get("message") ?? ""),
    };
  }

  if (contentType.includes("application/json")) {
    const json: unknown = await request.json();
    if (typeof json !== "object" || json === null) return null;
    const record = json as Record<string, unknown>;
    return {
      name: typeof record.name === "string" ? record.name : "",
      email: typeof record.email === "string" ? record.email : "",
      subject: typeof record.subject === "string" ? record.subject : "",
      message: typeof record.message === "string" ? record.message : "",
    };
  }

  return null;
};

export const POST: APIRoute = async ({ request, clientAddress }) => {
  const nowMs = Date.now();
  const ip = getClientIp(request, clientAddress);
  const rateKey = `contact:${ip}`;

  if (isRateLimited(rateKey, nowMs)) {
    return respondJson(429, {
      ok: false,
      error: {
        code: "rateLimited",
        message: "Demasiados intentos. Intenta de nuevo en un minuto.",
      },
    });
  }

  const raw = await readBody(request);
  if (!raw) {
    return respondJson(400, {
      ok: false,
      error: {
        code: "invalidRequest",
        message: "Solicitud inválida.",
      },
    });
  }

  const name = normalizeText(raw.name, 80);
  const email = normalizeText(raw.email, 254);
  const subject = normalizeText(raw.subject, 120);
  const message = normalizeText(raw.message, 4000);

  if (!name || !email || !subject || !message || !isEmailLike(email)) {
    return respondJson(400, {
      ok: false,
      error: {
        code: "invalidRequest",
        message: "Revisa los campos e inténtalo de nuevo.",
      },
    });
  }

  const resendApiKey = import.meta.env.RESEND_API_KEY as string | undefined;
  const contactToEmail = import.meta.env.CONTACT_TO_EMAIL as string | undefined;
  const contactFromEmail = import.meta.env.CONTACT_FROM_EMAIL as
    | string
    | undefined;

  if (!resendApiKey || !contactToEmail || !contactFromEmail) {
    console.log(resendApiKey, contactToEmail, contactFromEmail);
    return respondJson(501, {
      ok: false,
      error: {
        code: "notConfigured",
        message: "Contacto no está configurado todavía.",
      },
    });
  }

  const emailText = [
    "Nuevo mensaje desde resuely.com",
    "",
    `Nombre: ${name}`,
    `Correo: ${email}`,
    `Asunto: ${subject}`,
    "",
    "Mensaje:",
    message,
  ].join("\n");

  const resendPayload: Record<string, unknown> = {
    from: contactFromEmail,
    to: contactToEmail,
    subject: `[Resuely] ${subject}`,
    text: emailText,
  };
  resendPayload["reply_to"] = email;

  const response = await fetch("https://api.resend.com/emails", {
    method: "POST",
    headers: {
      authorization: `Bearer ${resendApiKey}`,
      "content-type": "application/json",
      accept: "application/json",
    },
    body: JSON.stringify(resendPayload),
  });

  if (!response.ok) {
    console.log(await response.json());
    return respondJson(502, {
      ok: false,
      error: {
        code: "emailFailed",
        message: "No pudimos enviar tu mensaje. Intenta de nuevo más tarde.",
      },
    });
  }

  return respondJson(200, { ok: true });
};

export const ALL: APIRoute = async () => {
  return respondJson(405, {
    ok: false,
    error: {
      code: "methodNotAllowed",
      message: "Método no permitido.",
    },
  });
};
