<!doctype html>

<html lang="en">

<head>

  <meta charset="utf-8" />

  <title>Clemelopy GEO Linking Map</title>

  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <script src="https://unpkg.com/@supabase/supabase-js@2"></script>

  <style>

    :root{

      --geo-bg:#ffffff; --geo-text:#1f2937; --geo-muted:#6b7280; --geo-border:#e5e7eb;

      --geo-line:#eceff3; --geo-teal:#00A99D; --geo-orange:#FAA819;

      --geo-shadow:0 8px 30px rgba(0,0,0,.06); --geo-radius:16px; --geo-focus:0 0 0 3px rgba(0,169,157,.25);

    }

    body{

      margin:0;

      padding:40px 0 60px;

      background:#f5f5f7;

      font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;

      color:var(--geo-text);

    }

    .geo-wrap{max-width:880px;margin:0 auto;padding:0 24px;}

    .geo-card{

      background:var(--geo-bg);

      border:1px solid var(--geo-border);

      border-radius:var(--geo-radius);

      box-shadow:var(--geo-shadow);

      padding:28px;

      margin-bottom:24px;

    }

    .geo-header{

      border-bottom:1px solid var(--geo-line);

      padding-bottom:14px;

      margin-bottom:16px;

    }

    .geo-header h1{

      margin:0 0 6px;

      font-size:26px;

      font-weight:700;

      letter-spacing:.2px;

    }

    .geo-sub{

      margin:0;

      font-size:14px;

      color:var(--geo-muted);

    }

    textarea{

      width:100%;

      min-height:180px;

      resize:vertical;

      border:1px solid var(--geo-border);

      border-radius:12px;

      padding:12px 14px;

      font-size:15px;

      line-height:1.6;

      background:#fff;

      transition:all .15s ease;

    }

    textarea:focus{

      outline:none;

      border-color:var(--geo-teal);

      box-shadow:var(--geo-focus);

    }

    .geo-btn-wrap{display:flex;justify-content:center;margin-top:14px;}

    .geo-btn{

      display:inline-flex;

      align-items:center;

      justify-content:center;

      background:var(--geo-teal);

      color:#fff;

      border:none;

      cursor:pointer;

      border-radius:999px;

      padding:12px 26px;

      min-width:200px;

      font-size:15px;

      font-weight:600;

      letter-spacing:.3px;

      transition:all .2s ease;

      box-shadow:0 3px 12px rgba(0,169,157,.25);

    }

    .geo-btn:hover{background:#008c83;transform:translateY(-2px);}

    .geo-btn:disabled{opacity:.7;cursor:not-allowed;transform:none;}

    #status{

      margin-top:10px;

      color:#777;

      font-size:.9em;

      text-align:center;

      min-height:1em;

    }

    .geo-project-card{

      display:flex;

      justify-content:space-between;

      align-items:center;

      padding:10px 0;

      border-bottom:1px solid var(--geo-line);

    }

    .geo-project-title{font-weight:600;font-size:14px;}

    .geo-project-date{font-size:12px;color:#9ca3af;}

    .geo-project-link{

      font-size:13px;

      color:#00A99D;

      text-decoration:none;

      font-weight:600;

    }

    .geo-project-link:hover{text-decoration:underline;}

    .billing-portal-wrap{margin-top:12px;}

    .billing-portal-btn{

      background-color:#FAA81A;

      color:#ffffff;

      font-weight:600;

      font-size:13px;

      padding:10px 22px;

      border:none;

      border-radius:999px;

      cursor:pointer;

      transition:all .25s ease;

      box-shadow:0 3px 12px rgba(250,168,26,0.25);

    }

    .billing-portal-btn:hover{

      background-color:#e69a15;

      transform:translateY(-2px);

    }

    .billing-portal-btn:disabled{

      opacity:.7;

      cursor:not-allowed;

      box-shadow:none;

      transform:none;

    }

    .auth-email, .auth-password{

      width:100%;

      padding:9px 10px;

      margin-bottom:6px;

      border-radius:8px;

      border:1px solid var(--geo-border);

      font-size:14px;

    }

    .auth-email:focus,

    .auth-password:focus{

      outline:none;

      border-color:var(--geo-teal);

      box-shadow:var(--geo-focus);

    }

    .auth-label{font-size:12px;color:#6b7280;margin-bottom:2px;}

    #authStatus{margin-top:6px;font-size:12px;color:#6b7280;min-height:1em;}

    .tagline{font-size:12px;color:#9ca3af;margin:0 0 6px;}

  </style>

</head>

<body>

<div class="geo-wrap">

  <!-- Auth -->

  <div class="geo-card" id="authCard">

    <p class="tagline">Clemelopy GEO Suite</p>

    <h3 style="margin:0 0 8px;">Sign in to generate your GEO Linking Map</h3>

    <div class="auth-label">Email</div>

    <input id="authEmail" class="auth-email" placeholder="you@example.com" />

    <div class="auth-label">Password</div>

    <input id="authPassword" class="auth-password" type="password" placeholder="Create or use an existing password" />

    <button id="loginBtn" class="geo-btn" style="min-width:170px;margin-top:4px;">Sign in / Create account</button>

    <div id="authStatus"></div>

  </div>


  <!-- Generator -->

  <div class="geo-card" id="generatorCard" style="display:none;">

    <header class="geo-header">

      <h1>Generate your GEO Linking Map</h1>

      <h3 class="geo-sub">

        Paste your full content below and queue the confetti! Once generated, you’ll receive a downloadable, GEO-optimized PDF.

      </h3>

    </header>

    <textarea id="content" placeholder="Paste your full content here"></textarea>

    <div class="geo-btn-wrap">

      <button id="generateBtn" class="geo-btn">Generate my map</button>

    </div>

    <p id="status"></p>

  </div>


  <!-- My Projects -->

  <div class="geo-card" id="projectsCard" style="display:none;">

    <h3 style="margin:0 0 10px;">My GEO Maps</h3>

    <div id="geoProjects"></div>

    <div class="billing-portal-wrap">

      <button id="manageSubscriptionBtn" class="billing-portal-btn">

        Manage my subscription

      </button>

    </div>

  </div>

</div>


<script>

  // ===== CONFIG =====

  const SUPABASE_URL = "YOUR_SUPABASE_URL";

  const SUPABASE_ANON_KEY = "YOUR_SUPABASE_ANON_KEY";

  const WORKER_ORIGIN = "YOUR_WORKER_URL"; // e.g. https://linking-strategy-map.jen-86f.workers.dev


  const supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);


  // ===== AUTH UI =====

  async function refreshUI() {

    const { data } = await supabase.auth.getSession();

    const session = data.session;

    const authed = !!session;


    document.getElementById("authCard").style.display      = authed ? "none"  : "block";

    document.getElementById("generatorCard").style.display = authed ? "block" : "none";

    document.getElementById("projectsCard").style.display  = authed ? "block" : "none";


    if (authed) {

      loadProjects();

    }

  }


  document.getElementById("loginBtn").onclick = async () => {

    const email = document.getElementById("authEmail").value.trim();

    const password = document.getElementById("authPassword").value.trim();

    const status = document.getElementById("authStatus");

    status.textContent = "";


    if (!email || !password) {

      status.textContent = "Enter email and password.";

      return;

    }


    // Try sign-in, if invalid then sign-up

    const { data, error } = await supabase.auth.signInWithPassword({ email, password });

    if (error && /Invalid login/i.test(error.message)) {

      const { error: signUpError } = await supabase.auth.signUp({ email, password });

      status.textContent = signUpError

        ? signUpError.message

        : "Check your email to confirm your account, then sign in.";

      return;

    }

    if (error) {

      status.textContent = error.message;

      return;

    }


    status.textContent = "";

    await refreshUI();

  };


  async function getAccessToken() {

    const { data } = await supabase.auth.getSession();

    return data.session?.access_token || null;

  }


  // ===== GENERATE =====

  document.getElementById("generateBtn").onclick = async () => {

    const content = document.getElementById("content").value.trim();

    const status = document.getElementById("status");

    const btn = document.getElementById("generateBtn");


    status.textContent = "";

    if (content.length < 300) {

      status.textContent = "Please paste at least 300 characters of content.";

      return;

    }


    const token = await getAccessToken();

    if (!token) {

      status.textContent = "Please log in again.";

      return;

    }


    btn.disabled = true;

    btn.textContent = "Generating...";


    try {

      const res = await fetch(WORKER_ORIGIN + "/generate", {

        method: "POST",

        headers: {

          "Content-Type": "application/json",

          "Authorization": "Bearer " + token

        },

        body: JSON.stringify({ content })

      });


      const data = await res.json().catch(() => ({}));


      if (res.status === 402 && (data.code === "PAYWALL" || /paywall/i.test(data.error || ""))) {

        status.textContent = data.error || "You’ve hit your limit. Please upgrade to continue.";

      } else if (!res.ok) {

        status.textContent = data.error || `Server error (${res.status})`;

      } else if (data.pdf_url) {

        window.open(data.pdf_url, "_blank", "noopener");

        status.textContent = "Your GEO Linking Map is ready.";

        document.getElementById("content").value = "";

        loadProjects();

      } else {

        status.textContent = "Completed, but no PDF URL returned.";

      }

    } catch (e) {

      console.error(e);

      status.textContent = "Network error. Please try again.";

    } finally {

      btn.disabled = false;

      btn.textContent = "Generate my map";

    }

  };


  // ===== MY PROJECTS =====

  async function loadProjects() {

    const root = document.getElementById("geoProjects");

    root.textContent = "Loading...";

    const token = await getAccessToken();

    if (!token) {

      root.textContent = "Please log in.";

      return;

    }


    try {

      const res = await fetch(WORKER_ORIGIN + "/my-projects", {

        method: "GET",

        headers: {

          "Authorization": "Bearer " + token

        }

      });

      const data = await res.json().catch(() => ({}));


      if (!res.ok || !data.ok) {

        console.error("My Projects error", data);

        root.textContent = "We couldn’t load your maps.";

        return;

      }


      const projects = data.projects || [];

      if (!projects.length) {

        root.textContent = "You don’t have any maps yet. Generate one to see it here.";

        return;

      }


      root.innerHTML = projects.map(p => {

        const created = p.created_at

          ? new Date(p.created_at).toLocaleDateString()

          : "";

        const title = p.title || "Untitled Project";

        const url = p.pdf_url || "#";


        return `

          <div class="geo-project-card">

            <div>

              <div class="geo-project-title">${title}</div>

              ${created ? `<div class="geo-project-date">${created}</div>` : ""}

            </div>

            ${url && url !== "#" ? `

            <a href="${url}" target="_blank" rel="noopener" class="geo-project-link">

              Download PDF

            </a>` : ""}

          </div>

        `;

      }).join("");

    } catch (e) {

      console.error(e);

      root.textContent = "Network error loading maps.";

    }

  }


  // ===== BILLING PORTAL =====

  document.getElementById("manageSubscriptionBtn").onclick = async () => {

    const btn = document.getElementById("manageSubscriptionBtn");

    const token = await getAccessToken();

    if (!token) {

      alert("Please log in to manage your subscription.");

      return;

    }


    btn.disabled = true;

    btn.textContent = "Opening portal...";


    try {

      const res = await fetch(WORKER_ORIGIN + "/billing/portal", {

        method: "POST",

        headers: {

          "Content-Type": "application/json",

          "Authorization": "Bearer " + token

        },

        body: JSON.stringify({})

      });

      const data = await res.json().catch(() => ({}));

      if (!res.ok || !data.url) {

        console.error("Billing portal error", data);

        alert("We couldn’t open your billing portal. Please contact support.");

      } else {

        window.open(data.url, "_blank", "noopener");

      }

    } catch (e) {

      console.error(e);

      alert("Network error. Please try again.");

    } finally {

      btn.disabled = false;

      btn.textContent = "Manage my subscription";

    }

  };


  // init

  refreshUI();

  supabase.auth.onAuthStateChange((_event, _session) => { refreshUI(); });

</script>

</body>

</html>