// functions/contact/index.ts

declare global {
  interface KVNamespace {
    get(key: string): Promise<string | null>;
    put(
      key: string,
      value: string,
      options?: { expirationTtl?: number },
    ): Promise<void>;
  }
}

interface Env {
  RESEND_API_KEY: string;
  EMAILS_API: string;
  EMAILS_TO: string;
  EMAILS_TO_CC: string;
  EMAILS_FROM: string;
  TURNSTILE_SECRET_KEY?: string;
  RATE_LIMIT_KV?: KVNamespace;
}

function escapeHtml(input: unknown): string {
  return String(input ?? "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#39;");
}

function safeEmailHref(email: string): string {
  return `mailto:${encodeURIComponent(email)}`;
}

type Validated = {
  fullName: string;
  email: string;
  phone?: string;
  subject: "job-application" | "suggestion" | "something-else";
  subjectOther?: string;
  message: string;
  consent: boolean;
};

function validatePayload(
  body: any,
): { ok: true; value: Validated } | { ok: false; error: string } {
  if (!body || typeof body !== "object") {
    return { ok: false, error: "Invalid payload" };
  }

  const fullName = String(body.fullName ?? "").trim();

  if (fullName.length < 4 || fullName.length > 100) {
    return { ok: false, error: "Invalid name length" };
  }

  const email = String(body.email ?? "").trim();
  const emailRe = /^(?:[^\s@]+)@(?:[^\s@]+)\.[^\s@]{2,}$/i;

  if (!emailRe.test(email) || email.length > 254) {
    return { ok: false, error: "Invalid email" };
  }

  const phone = String(body.phone ?? "").trim();

  if (phone) {
    const phoneRe =
      /^\+?[1-9]\d{0,3}[\s\-().]?\d{1,4}[\s\-().]?\d{1,4}[\s\-().]?\d{1,9}$/;

    if (!phoneRe.test(phone) || phone.length > 30) {
      return { ok: false, error: "Invalid phone" };
    }
  }

  const subject = String(body.subject ?? "");
  const allowedSubjects = ["job-application", "suggestion", "something-else"];

  if (!allowedSubjects.includes(subject)) {
    return { ok: false, error: "Invalid subject" };
  }

  const subjectOther = String(body.subjectOther ?? "").trim();

  if (subject === "something-else" && subjectOther.length === 0) {
    return { ok: false, error: "Subject other required" };
  }

  if (subjectOther.length > 120) {
    return { ok: false, error: "subjectOther too long" };
  }

  const message = String(body.message ?? "").trim();

  if (message.length < 25 || message.length > 600) {
    return { ok: false, error: "Invalid message length" };
  }

  const consent = Boolean(body.consent);

  if (!consent) {
    return { ok: false, error: "Consent required" };
  }

  return {
    ok: true,
    value: {
      fullName,
      email,
      phone,
      subject: subject as Validated["subject"],
      subjectOther,
      message,
      consent,
    },
  };
}

function isAllowedOrigin(request: Request): boolean {
  const origin = request.headers.get("Origin") || "";

  const allowed = ["https://mucomutfak.com", "https://www.mucomutfak.com"];

  if (!origin) return true;

  return allowed.includes(origin);
}

async function verifyTurnstile(
  secret: string | undefined,
  token: string | undefined,
  remoteIp?: string,
) {
  if (!secret) return { ok: false, error: "Turnstile not configured" };
  if (!token) return { ok: false, error: "Missing Turnstile token" };

  try {
    const form = new URLSearchParams();

    form.set("secret", secret);
    form.set("response", token);

    if (remoteIp) {
      form.set("remoteip", remoteIp);
    }

    const res = await fetch(
      "https://challenges.cloudflare.com/turnstile/v0/siteverify",
      {
        method: "POST",
        body: form,
      },
    );

    const json = await res.json();

    if (json.success) {
      return { ok: true };
    }

    return {
      ok: false,
      error: "Turnstile failed",
      details: json["error-codes"] || json,
    };
  } catch {
    return { ok: false, error: "Turnstile verification error" };
  }
}

async function rateLimitCheck(
  ip: string | null,
  kv: KVNamespace | undefined,
): Promise<{ ok: true } | { ok: false; retryAfter?: number }> {
  if (!kv || !ip) return { ok: true };

  const key = `cf_rl:${ip}:${new Date().toISOString().slice(0, 16)}`;

  try {
    const existing = await kv.get(key);
    const count = existing ? parseInt(existing, 10) : 0;
    const limitPerMinute = 6;

    if (count >= limitPerMinute) {
      return { ok: false, retryAfter: 60 };
    }

    await kv.put(key, String(count + 1), {
      expirationTtl: 65,
    });

    return { ok: true };
  } catch (e) {
    console.error("KV rate limit error", e);
    return { ok: true };
  }
}

export async function onRequestPost({
  request,
  env,
}: {
  request: Request;
  env: Env;
}) {
  try {
    console.log("[contact] function invoked", {
      origin: request.headers.get("Origin"),
      hasSecret: !!env.TURNSTILE_SECRET_KEY,
      hasKV: !!env.RATE_LIMIT_KV,
    });

    if (!isAllowedOrigin(request)) {
      return new Response(
        JSON.stringify({
          success: false,
          error: "Forbidden",
        }),
        {
          status: 403,
          headers: {
            "Content-Type": "application/json",
          },
        },
      );
    }

    const body = await request.json().catch(() => null);

    if (body?.checkIfYouAreNotARobot) {
      console.warn("Robot triggered from request");

      return new Response(
        JSON.stringify({
          success: true,
        }),
        {
          headers: {
            "Content-Type": "application/json",
          },
        },
      );
    }

    const validated = validatePayload(body);

    if (!validated.ok) {
      return new Response(
        JSON.stringify({
          success: false,
          error: validated.error,
        }),
        {
          status: 400,
          headers: {
            "Content-Type": "application/json",
          },
        },
      );
    }

    const data = validated.value;

    const ip =
      request.headers.get("cf-connecting-ip") ||
      request.headers.get("x-forwarded-for") ||
      null;

    const rateLimit = await rateLimitCheck(ip, env.RATE_LIMIT_KV);

    if (!rateLimit.ok) {
      return new Response(
        JSON.stringify({
          success: false,
          error: "Rate limit exceeded",
        }),
        {
          status: 429,
          headers: {
            "Content-Type": "application/json",
          },
        },
      );
    }

    const turnstileToken = String(body?.turnstileToken ?? "");

    if (env.TURNSTILE_SECRET_KEY) {
      console.log("[contact] using TURNSTILE_SECRET_KEY");

      const turnstile = await verifyTurnstile(
        env.TURNSTILE_SECRET_KEY,
        turnstileToken,
        ip || undefined,
      );

      if (!turnstile.ok) {
        console.warn("Turnstile failed", turnstile);

        return new Response(
          JSON.stringify({
            success: false,
            error: "Bot verification failed",
          }),
          {
            status: 400,
            headers: {
              "Content-Type": "application/json",
            },
          },
        );
      }
    }

    const subjectLine =
      data.subject === "something-else"
        ? data.subjectOther || "Contact Form"
        : data.subject;

    const receivedAt = new Date().toISOString();
    const sourceOrigin =
      request.headers.get("Origin") || request.headers.get("Referer") || "N/A";
    const clientIp = ip || "N/A";
    const subjectOtherSafe =
      data.subject === "something-else" ? data.subjectOther || "" : "";
    const consentText = data.consent ? "Yes" : "No";
    const phoneText = data.phone || "-";

    const quotedMessage = String(data.message)
      .split("\n")
      .map((line) => `> ${line}`)
      .join("\n");

    const mailText = `
Yeni Mesajınız Var!

── İletişim Detayları ─────────────────────
Ad Soyad: ${data.fullName}
E-posta: ${data.email}
Telefon: ${phoneText}
Konu: ${subjectLine} ${subjectOtherSafe ? " - " + subjectOtherSafe : ""}
İletişim İzni: ${consentText}

── Mesaj ─────────────────────────────
${data.message}

── Meta ─────────────────────────────────
Origin: ${sourceOrigin}
IP: ${clientIp}
Tarih: ${receivedAt}

── Yanıtla ─
> Ad Soyad: ${data.fullName}
> E-posta: ${data.email}
> Telefon: ${phoneText}
> Konu: ${subjectLine} ${subjectOtherSafe ? " - " + subjectOtherSafe : ""}
>
${quotedMessage}
`;

    const mailHtml = `
<!doctype html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <style>
      .wrapper { width:100%; background:#f5f7fb; margin:0; padding:24px 12px; }
      .container { width:100%; max-width:640px; margin:0 auto; background:#ffffff; border-radius:12px; border:1px solid #e5e7eb; overflow:hidden; }
      .header { padding:20px 24px; background:#0f172a; color:#ffffff; }
      .title { margin:0; font-size:20px; line-height:1.3; }
      .section { padding:20px 24px; }
      .kv { width:100%; border-collapse:collapse; }
      .kv th { text-align:left; padding:8px 0; font-size:13px; color:#64748b; width:160px; vertical-align:top; }
      .kv td { padding:8px 0; font-size:14px; color:#0f172a; }
      .divider { height:1px; background:#e5e7eb; margin:12px 0; }
      .message { white-space:pre-wrap; padding:12px; border-radius:8px; background:#f8fafc; border:1px solid #e2e8f0; color:#0f172a; font-size:14px; }
      .footer { padding:16px 24px; font-size:12px; color:#94a3b8; background:#fafafa; }
      .pill { display:inline-block; padding:4px 10px; border-radius:9999px; border:1px solid #e2e8f0; font-size:12px; color:#0f172a; background:#f8fafc; }
      .btn { display:inline-block; font-size:14px; text-decoration:none; padding:10px 14px; border-radius:8px; border:1px solid #0f172a; }
      @media (max-width: 480px) {
        .section { padding:16px; }
        .header { padding:16px; }
        .kv th { width:120px; }
      }
    </style>
  </head>
  <body style="margin:0; padding:0; background:#f5f7fb;">
    <div class="wrapper">
      <table role="presentation" class="container" cellpadding="0" cellspacing="0">
        <tr>
          <td class="header">
            <h2 class="title">Yeni Mesajınız Var!</h2>
            <div style="margin-top:8px;">
              <span class="pill">${escapeHtml(subjectLine)}</span>
            </div>
          </td>
        </tr>

        <tr>
          <td class="section">
            <table class="kv" role="presentation">
              <tr>
                <th>Ad Soyad</th>
                <td>${escapeHtml(data.fullName)}</td>
              </tr>

              <tr>
                <th>E-posta</th>
                <td>
                  <a href="${safeEmailHref(data.email)}" style="color:#0f172a;">
                    ${escapeHtml(data.email)}
                  </a>
                </td>
              </tr>

              <tr>
                <th>Telefon</th>
                <td>${escapeHtml(phoneText)}</td>
              </tr>

              <tr>
                <th>Konu</th>
                <td>
                  ${escapeHtml(subjectLine)}
                  ${subjectOtherSafe ? " - " + escapeHtml(subjectOtherSafe) : ""}
                </td>
              </tr>

              <tr>
                <th>İletişim İzni</th>
                <td>${escapeHtml(consentText)}</td>
              </tr>
            </table>

            <div style="margin-bottom:6px;">Mesaj</div>

            <div class="message">
              ${escapeHtml(data.message)}
            </div>

            <div class="divider"></div>

            <div style="font-weight:600; margin-bottom:6px;">
              Reply-ready quote
            </div>

            <blockquote style="margin:0; padding-left:12px; border-left:3px solid #e2e8f0; color:#334155;">
              <div>
                <strong>Kimden:</strong>
                ${escapeHtml(data.fullName)} &lt;${escapeHtml(data.email)}&gt;
              </div>

              <div>
                <strong>Telefon:</strong>
                ${escapeHtml(phoneText)}
              </div>

              <div>
                <strong>Konu:</strong>
                ${escapeHtml(subjectLine)}
                ${subjectOtherSafe ? " - " + escapeHtml(subjectOtherSafe) : ""}
              </div>

              <div style="margin-top:8px; white-space:pre-wrap;">
                ${escapeHtml(data.message)}
              </div>
            </blockquote>

            <div style="margin-top:16px;">
              <a class="btn" href="${safeEmailHref(data.email)}">
                Yanıtla ${escapeHtml(data.fullName)}
              </a>
            </div>
          </td>
        </tr>

        <tr>
          <td class="section" style="padding-top:0;">
            <table class="kv" role="presentation">
              <tr>
                <th>Origin</th>
                <td>${escapeHtml(sourceOrigin)}</td>
              </tr>

              <tr>
                <th>IP</th>
                <td>${escapeHtml(clientIp)}</td>
              </tr>

              <tr>
                <th>Tarih</th>
                <td>${escapeHtml(receivedAt)}</td>
              </tr>
            </table>
          </td>
        </tr>

        <tr>
          <td class="footer">
            Bu e-posta iletişim formundan otomatik olarak gönderilmiştir.
          </td>
        </tr>
      </table>
    </div>
  </body>
</html>`;

    const cc = env.EMAILS_TO_CC
      ? env.EMAILS_TO_CC.split(",")
          .map((email) => email.trim())
          .filter(Boolean)
      : [];

    const mailResponse = await fetch(env.EMAILS_API, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${env.RESEND_API_KEY}`,
      },
      body: JSON.stringify({
        from: env.EMAILS_FROM,
        to: [env.EMAILS_TO],
        cc,
        subject: `Yeni Mesajınız Var: ${subjectLine}${
          subjectOtherSafe ? " - " + subjectOtherSafe : ""
        }`,
        text: mailText,
        html: mailHtml,
        reply_to: data.email,
      }),
    });

    if (!mailResponse.ok) {
      const detail = await mailResponse.text().catch(() => "no details");

      console.error("Resend error:", mailResponse.status, detail);

      return new Response(
        JSON.stringify({
          success: false,
          error: "Unable to send message",
        }),
        {
          status: 500,
          headers: {
            "Content-Type": "application/json",
          },
        },
      );
    }

    const responseJson = await mailResponse.json().catch(() => ({}));

    return new Response(
      JSON.stringify({
        success: true,
        id: responseJson.id || null,
      }),
      {
        headers: {
          "Content-Type": "application/json",
        },
      },
    );
  } catch (err) {
    console.error("Unhandled error in contact function", err);

    return new Response(
      JSON.stringify({
        success: false,
        error: "Server error",
      }),
      {
        status: 500,
        headers: {
          "Content-Type": "application/json",
        },
      },
    );
  }
}