type Env = {
    TURNSTILE_SECRET_KEY?: string;
    RESEND_API_KEY?: string;
    CONTACT_FROM_EMAIL?: string;
    CONTACT_TO_EMAIL?: string;
};

const jsonResponse = (data: Record<string, unknown>, status = 200) =>
    new Response(JSON.stringify(data), {
        status,
        headers: { "content-type": "application/json" },
    });

const fetchWithTimeout = async (
    input: RequestInfo | URL,
    init: RequestInit,
    timeoutMs: number,
    label: string,
) => {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), timeoutMs);
    try {
        return await fetch(input, { ...init, signal: controller.signal });
    } catch (error) {
        const message =
            error instanceof Error ? error.message : "Unknown error";
        throw new Error(`${label} request failed: ${message}`);
    } finally {
        clearTimeout(timeout);
    }
};

const readFormField = (value: FormDataEntryValue | null) =>
    typeof value === "string" ? value.trim() : "";
const readTextField = (value: string | null) => (value ?? "").trim();

const parseFormFields = async (request: Request) => {
    const contentType = request.headers.get("content-type") ?? "";
    if (contentType.includes("application/x-www-form-urlencoded")) {
        const bodyText = await request.text();
        const params = new URLSearchParams(bodyText);
        return {
            name: readTextField(params.get("name")),
            email: readTextField(params.get("email")),
            message: readTextField(params.get("message")),
            turnstileToken: readTextField(params.get("cf-turnstile-response")),
        };
    }

    const formData = await request.formData();
    return {
        name: readFormField(formData.get("name")),
        email: readFormField(formData.get("email")),
        message: readFormField(formData.get("message")),
        turnstileToken: readFormField(formData.get("cf-turnstile-response")),
    };
};

const handlePost: PagesFunction<Env> = async ({ request, env }) => {
    const { name, email, message, turnstileToken } =
        await parseFormFields(request);

    if (!name || !email || !message) {
        return jsonResponse(
            { ok: false, error: "Missing required fields." },
            400,
        );
    }

    if (!env.TURNSTILE_SECRET_KEY) {
        return jsonResponse(
            { ok: false, error: "Turnstile secret key not configured." },
            500,
        );
    }

    if (!turnstileToken) {
        return jsonResponse(
            { ok: false, error: "Turnstile verification failed." },
            400,
        );
    }

    const verifyBody = new URLSearchParams({
        secret: env.TURNSTILE_SECRET_KEY,
        response: turnstileToken,
        remoteip: request.headers.get("CF-Connecting-IP") ?? "",
    });

    const verifyResponse = await fetchWithTimeout(
        "https://challenges.cloudflare.com/turnstile/v0/siteverify",
        {
            method: "POST",
            headers: { "content-type": "application/x-www-form-urlencoded" },
            body: verifyBody,
        },
        8000,
        "Turnstile",
    );
    const verifyResult = (await verifyResponse.json()) as {
        success?: boolean;
        "error-codes"?: string[];
        messages?: string[];
        hostname?: string;
        action?: string;
        cdata?: string;
    };

    if (!verifyResult.success) {
        const details = [
            verifyResult["error-codes"]?.length
                ? `codes=${verifyResult["error-codes"].join(",")}`
                : "",
            verifyResult.messages?.length
                ? `messages=${verifyResult.messages.join(",")}`
                : "",
            verifyResult.hostname ? `hostname=${verifyResult.hostname}` : "",
            verifyResult.action ? `action=${verifyResult.action}` : "",
        ]
            .filter(Boolean)
            .join(" | ")
            .slice(0, 500);
        return jsonResponse(
            {
                ok: false,
                error: "Turnstile verification failed.",
                details: details || undefined,
            },
            400,
        );
    }

    if (!env.RESEND_API_KEY) {
        return jsonResponse(
            { ok: false, error: "Email provider not configured." },
            500,
        );
    }

    const fromEmail = env.CONTACT_FROM_EMAIL;
    if (!fromEmail) {
        return jsonResponse(
            { ok: false, error: "Sender email not configured." },
            500,
        );
    }

    const toEmail = env.CONTACT_TO_EMAIL ?? "calum@muir.in";

    const emailPayload = {
        from: fromEmail,
        to: [toEmail],
        reply_to: email,
        subject: "New contact form submission",
        text: `Name: ${name}\nEmail: ${email}\n\n${message}`,
    };

    const response = await fetchWithTimeout(
        "https://api.resend.com/emails",
        {
            method: "POST",
            headers: {
                Authorization: `Bearer ${env.RESEND_API_KEY}`,
                "Content-Type": "application/json",
            },
            body: JSON.stringify(emailPayload),
        },
        8000,
        "Resend",
    );
    if (!response.ok) {
        const contentType = response.headers.get("content-type") ?? "";
        const errorText = contentType.includes("application/json")
            ? JSON.stringify(await response.json().catch(() => ({})))
            : await response.text();
        const errorCode = response.headers.get("x-ms-error-code");
        const details = [
            `${response.status} ${response.statusText}`.trim(),
            errorCode ? `code=${errorCode}` : "",
            errorText.trim(),
        ]
            .filter(Boolean)
            .join(" | ")
            .slice(0, 500);
        return jsonResponse(
            {
                ok: false,
                error: "Failed to send email.",
                details,
            },
            502,
        );
    }

    return jsonResponse({ ok: true });
};

export const onRequest: PagesFunction<Env> = async (context) => {
    try {
        if (context.request.method !== "POST") {
            return jsonResponse(
                { ok: false, error: "Method not allowed." },
                405,
            );
        }
        return await handlePost(context);
    } catch (error) {
        const message =
            error instanceof Error ? error.message : "Unknown error";
        return jsonResponse(
            { ok: false, error: "Unhandled exception.", details: message },
            500,
        );
    }
};
