import { createServerFn } from "@tanstack/react-start";
import { getRequest } from "@tanstack/react-start/server";
import { createClient } from "@supabase/supabase-js";
import { createHash } from "node:crypto";
import { z } from "zod";
import type { Database } from "@/integrations/supabase/types";

function publicClient() {
  const key = process.env.SUPABASE_PUBLISHABLE_KEY!;
  return createClient<Database>(process.env.SUPABASE_URL!, key, {
    auth: { persistSession: false, autoRefreshToken: false },
    global: {
      fetch: (input, init) => {
        const h = new Headers(init?.headers);
        if (key.startsWith("sb_") && h.get("Authorization") === `Bearer ${key}`) {
          h.delete("Authorization");
        }
        h.set("apikey", key);
        return fetch(input, { ...init, headers: h });
      },
    },
  });
}

export const contactSchema = z.object({
  name: z.string().trim().min(1, "Please enter your name").max(100),
  email: z.string().trim().email("Enter a valid email address").max(255),
  company: z.string().trim().max(120).optional().or(z.literal("")),
  message: z.string().trim().min(10, "Tell us a bit more about your project").max(2000),
  source: z.string().trim().max(60).optional(),
  /** Honeypot — must stay empty; bots fill it in. */
  website: z.string().max(200).optional().or(z.literal("")),
  /** Milliseconds the visitor spent on the form before submitting. */
  elapsedMs: z.number().int().nonnegative().max(86_400_000).optional(),
  /** Cloudflare Turnstile token, when CAPTCHA is configured. */
  captchaToken: z.string().max(4000).optional().or(z.literal("")),
});

export type ContactInput = z.infer<typeof contactSchema>;

export type ContactResult =
  | { ok: true }
  | { ok: false; reason: "rate_limited" | "spam" | "captcha" | "error"; message: string };

function clientIpHash(): string | null {
  try {
    const req = getRequest();
    const raw =
      req.headers.get("cf-connecting-ip") ??
      req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ??
      req.headers.get("x-real-ip");
    if (!raw) return null;
    return createHash("sha256").update(`gatavase:${raw}`).digest("hex").slice(0, 64);
  } catch {
    return null;
  }
}

async function verifyCaptcha(token: string | undefined, ip: string | null) {
  const secret = process.env.TURNSTILE_SECRET_KEY;
  if (!secret) return true; // CAPTCHA not configured yet — honeypot + rate limit still apply.
  if (!token) return false;
  try {
    const res = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ secret, response: token, remoteip: ip ?? undefined }),
    });
    const body = (await res.json()) as { success?: boolean };
    return body.success === true;
  } catch (e) {
    console.error("turnstile verification failed", e);
    return false;
  }
}

export const submitContact = createServerFn({ method: "POST" })
  .inputValidator((data: ContactInput) => contactSchema.parse(data))
  .handler(async ({ data }): Promise<ContactResult> => {
    const supabase = publicClient();
    const ipHash = clientIpHash();

    const log = async (outcome: string, reason: string | null) => {
      try {
        await supabase.rpc("log_contact_event", {
          _outcome: outcome,
          _reason: reason ?? "",
          _email: data.email,
          _ip_hash: ipHash ?? "",
        });
      } catch (e) {
        console.error("contact event logging failed", e);
      }
    };

    // 1. Honeypot + submission-speed heuristics (free, catches most bots).
    if ((data.website ?? "").trim() !== "" || (data.elapsedMs ?? 99_999) < 2500) {
      await log("rejected", "honeypot");
      console.warn("[contact] rejected: honeypot/timing");
      // Answer as if accepted so bots gain no signal.
      return { ok: true };
    }

    // 2. CAPTCHA (active once TURNSTILE_SECRET_KEY is configured).
    if (!(await verifyCaptcha(data.captchaToken || undefined, ipHash))) {
      await log("rejected", "captcha");
      return {
        ok: false,
        reason: "captcha",
        message: "Please complete the verification challenge and try again.",
      };
    }

    // 3. Rate limit: max 1 submission per minute and 3 per hour, per email or visitor.
    const { data: limited, error: limitError } = await supabase.rpc("contact_rate_limited", {
      _email: data.email,
      _ip_hash: ipHash ?? "",
    });
    if (limitError) console.error("rate limit check failed", limitError);
    if (limited === true) {
      await log("rejected", "rate_limited");
      return {
        ok: false,
        reason: "rate_limited",
        message: "You've already sent us a message. Please wait a few minutes before sending another.",
      };
    }

    const { error } = await supabase.from("contact_submissions").insert({
      name: data.name,
      email: data.email,
      company: data.company || null,
      message: data.message,
      source: data.source || "website",
      ip_hash: ipHash,
    });

    if (error) {
      console.error("contact insert failed", error);
      await log("failed", "db_insert");
      return {
        ok: false,
        reason: "error",
        message: "We could not save your message. Please email gazmanadvancedtechnologies@gmail.com.",
      };
    }

    await log("accepted", null);

    try {
      const { notifyNewLead } = await import("./notify.server");
      await notifyNewLead(data);
    } catch (notifyError) {
      // A failed notification must never lose the lead — it is already stored.
      console.error("lead notification failed", notifyError);
      await log("notify_failed", "email_provider");
    }

    return { ok: true };
  });
