import { ConvexAuthProvider, useAuthActions } from "@convex-dev/auth/react";
import {
  Authenticated,
  AuthLoading,
  ConvexReactClient,
  Unauthenticated,
  useConvex,
  useQuery,
} from "convex/react";
import { makeFunctionReference } from "convex/server";
import React, { useEffect, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";
import { readCart, writeCart } from "./commerce.js";
import "./storefront.css";

const deploymentUrl = import.meta.env.VITE_CONVEX_URL;
const subscribeRef = makeFunctionReference("subscribers:subscribe");
const createOrderRef = makeFunctionReference("orders:create");
const quoteRef = makeFunctionReference("orders:quote");
const adminOrdersRef = makeFunctionReference("admin:listOrders");
const adminSubscribersRef = makeFunctionReference("admin:listSubscribers");
const adminReviewsRef = makeFunctionReference("admin:listReviews");
const adminCheckRef = makeFunctionReference("admin:isAdmin");
const adminAddReviewRef = makeFunctionReference("admin:addReview");
const adminDeleteReviewRef = makeFunctionReference("admin:deleteReview");
const adminSeedReviewsRef = makeFunctionReference("admin:seedLegacyReviews");
const updateStatusRef = makeFunctionReference("admin:updateStatus");
const adminInventoryRef = makeFunctionReference("admin:listInventory");
const setStockRef = makeFunctionReference("admin:setStock");
const adminProductLabelsRef = makeFunctionReference("admin:listProductLabels");
const setProductLabelsRef = makeFunctionReference("admin:setProductLabels");
const myOrdersRef = makeFunctionReference("orders:mine");
const markPaymentSentRef = makeFunctionReference("orders:markPaymentSent");
const myProfileRef = makeFunctionReference("customers:myProfile");
const saveProfileRef = makeFunctionReference("customers:saveMyProfile");
const cancelMyOrderRef = makeFunctionReference("orders:cancelMine");
const publicInventoryRef = makeFunctionReference("inventory:forProduct");
const publicReviewsRef = makeFunctionReference("reviews:forProduct");
const submitReviewRef = makeFunctionReference("reviews:submit");
const peso = new Intl.NumberFormat("en-PH", {
  style: "currency",
  currency: "PHP",
  maximumFractionDigits: 0,
});

if (deploymentUrl && location.pathname.endsWith("item.html")) {
  const productId = new URLSearchParams(location.search).get("id");
  if (productId) {
    const publicClient = new ConvexReactClient(deploymentUrl);
    window.toCCInventoryPromise = publicClient
      .query(publicInventoryRef, { productId })
      .then((stock) => {
        window.toCCLatestStock = stock;
        window.dispatchEvent(
          new CustomEvent("to-cc-live-stock", { detail: stock }),
        );
        return stock;
      });
    window.toCCReviewPromise = publicClient
      .query(publicReviewsRef, { productId })
      .then((reviews) => {
        window.dispatchEvent(
          new CustomEvent("to-cc-live-reviews", { detail: reviews }),
        );
        return reviews;
      });
  }
}

function Newsletter({ client }) {
  const [open, setOpen] = useState(false);
  const [message, setMessage] = useState("");
  useEffect(() => {
    if (
      localStorage.getItem("to_cc_welcome10") === "true" ||
      sessionStorage.getItem("to_cc_newsletter_closed") === "true"
    )
      return;
    const timer = window.setTimeout(() => setOpen(true), 1200);
    return () => window.clearTimeout(timer);
  }, []);
  function close() {
    sessionStorage.setItem("to_cc_newsletter_closed", "true");
    setOpen(false);
  }
  async function submit(event) {
    event.preventDefault();
    const email = new FormData(event.currentTarget).get("email");
    if (!client) {
      setMessage("Email signup will be ready as soon as Convex is connected.");
      return;
    }
    setMessage("Joining…");
    try {
      await client.mutation(subscribeRef, { email });
      localStorage.setItem("to_cc_welcome10", "true");
      window.dispatchEvent(new Event("to-cc-discount-change"));
      setMessage("Welcome to the list — your 10% welcome offer is ready.");
      event.currentTarget.reset();
      window.setTimeout(() => setOpen(false), 1800);
    } catch {
      setMessage("Please check your email and try again.");
    }
  }
  if (!open) return null;
  return (
    <div
      className="to-newsletter-backdrop"
      role="presentation"
      onMouseDown={(event) => {
        if (event.target === event.currentTarget) close();
      }}
    >
      <section
        className="to-newsletter-modal"
        role="dialog"
        aria-modal="true"
        aria-labelledby="newsletter-title"
      >
        <button
          className="to-newsletter-close"
          type="button"
          onClick={close}
          aria-label="Close offer"
        >
          ×
        </button>
        <p className="to-eyebrow">A private invitation</p>
        <h2 id="newsletter-title">Enjoy 10% off</h2>
        <p>
          Enter your email for 10% off your first order, private collection
          previews, and considered notes from To:CC.
        </p>
        <form onSubmit={submit}>
          <label htmlFor="newsletter-email">Enter email here</label>
          <div>
            <input
              id="newsletter-email"
              name="email"
              type="email"
              required
              autoComplete="email"
              placeholder="you@example.com"
              autoFocus
            />
            <button>Unlock 10% off</button>
          </div>
        </form>
        {message && (
          <p className="to-newsletter-message" role="status">
            {message}
          </p>
        )}
        <small>
          By joining, you agree to receive occasional emails. Unsubscribe
          anytime.
        </small>
      </section>
    </div>
  );
}

function CommunitySignup({ client }) {
  const [message, setMessage] = useState("");
  async function submit(event) {
    event.preventDefault();
    const email = new FormData(event.currentTarget).get("email");
    if (!client) {
      setMessage("Connect Convex to activate signup.");
      return;
    }
    setMessage("Joining…");
    try {
      await client.mutation(subscribeRef, { email });
      localStorage.setItem("to_cc_welcome10", "true");
      window.dispatchEvent(new Event("to-cc-discount-change"));
      event.currentTarget.reset();
      setMessage("You’re in — your 10% welcome offer is ready.");
    } catch {
      setMessage("Please check your email and try again.");
    }
  }
  return (
    <form className="to-community-signup-form" onSubmit={submit}>
      <div>
        <label htmlFor="community-email">Email address</label>
        <input
          id="community-email"
          name="email"
          type="email"
          required
          placeholder="Enter your email"
          autoComplete="email"
        />
      </div>
      <button>Join now</button>
      {message && <p role="status">{message}</p>}
    </form>
  );
}

function SignInInline() {
  const { signIn } = useAuthActions();
  const [error, setError] = useState("");
  async function submit(event) {
    event.preventDefault();
    setError("");
    try {
      const fd = new FormData(event.currentTarget);
      fd.set("flow", "signIn");
      await signIn("password", fd);
    } catch {
      setError("We couldn't sign you in. Check your details and try again.");
    }
  }
  return (
    <div className="to-panel">
      <h2>Sign in to complete your order</h2>
      <p className="to-notice">
        Your basket stays on this device. Signing in lets us protect your order
        details and status.
      </p>
      <form onSubmit={submit} style={{ marginTop: "1.5rem" }}>
        <label className="to-field">
          Email
          <input name="email" type="email" autoComplete="email" required />
        </label>
        <label className="to-field">
          Password
          <input
            name="password"
            type="password"
            autoComplete="current-password"
            required
          />
        </label>
        {error && <p className="to-notice">{error}</p>}
        <button className="to-primary">Sign in</button>
      </form>
    </div>
  );
}

function PaymentOptions() {
  return (
    <div className="to-payment-dropdowns">
      {[{ label: "GCash" }, { label: "Bank transfer" }].map((option, index) => (
        <details key={option.label} open={index === 0}>
          <summary>
            <span>{option.label}</span>
            <i aria-hidden="true"></i>
          </summary>
          <div>
            <p>Name: Account Name</p>
            <p>Number: 0000 000 0000</p>
            <span className="to-qr-placeholder">
              QR SCREENSHOT
              <br />
              PLACEHOLDER
            </span>
          </div>
        </details>
      ))}
    </div>
  );
}

function CheckoutForm({ products, cart, setCart }) {
  const client = useConvex();
  const paymentMethod = "manual_payment";
  const [busy, setBusy] = useState(false);
  const [order, setOrder] = useState(null);
  const lines = cart
    .map((line) => ({ ...line, product: products.items[line.productId] }))
    .filter((line) => line.product);
  const quoteItems = useMemo(
    () =>
      cart.map(({ productId, color, size, quantity }) => ({
        productId,
        color,
        size,
        quantity,
      })),
    [cart],
  );
  const quote = useQuery(quoteRef, { items: quoteItems });
  const subtotal =
    quote?.subtotal ??
    lines.reduce(
      (sum, line) => sum + line.product.priceValue * line.quantity,
      0,
    );
  const discount = quote?.discount ?? 0;

  function changeQuantity(index, delta) {
    const next = [...cart];
    next[index].quantity = Math.max(
      0,
      Math.min(next[index].stock, next[index].quantity + delta),
    );
    const cleaned = next.filter((line) => line.quantity > 0);
    setCart(cleaned);
    writeCart(cleaned);
  }

  async function submit(event) {
    event.preventDefault();
    setBusy(true);
    const fd = new FormData(event.currentTarget);
    try {
      const result = await client.mutation(createOrderRef, {
        items: quoteItems,
        shipping: {
          fullName: fd.get("fullName"),
          phone: fd.get("phone"),
          address: fd.get("address"),
          city: fd.get("city"),
          postalCode: fd.get("postalCode"),
          instagram: fd.get("instagram"),
        },
        paymentMethod,
      });
      setOrder(result);
      writeCart([]);
      setCart([]);
    } catch {
      alert(
        "We couldn't place the order. Stock may have changed—please refresh and try again.",
      );
    } finally {
      setBusy(false);
    }
  }

  if (order) {
    const subject = encodeURIComponent(
      `Proof of payment for order ${order.orderNumber}`,
    );
    const body = encodeURIComponent(
      `Hello To:CC,\n\nAttached is my proof of payment for order ${order.orderNumber}.\nOrder total excluding shipping: ${peso.format(order.total)}\nAccount name: \n\nThank you.`,
    );
    async function confirmSent() {
      await client.mutation(markPaymentSentRef, { orderId: order.orderId });
      setOrder({ ...order, status: "payment_sent" });
    }
    return (
      <div className="to-panel to-order-received">
        <p className="to-eyebrow">Order created</p>
        <h2>{order.orderNumber}</h2>
        <p className="to-notice">
          Open either payment option below, then email the proof with the
          subject “Proof of payment for order {order.orderNumber}”.
        </p>
        <div className="to-summary-row to-summary-total">
          <span>Total excluding shipping</span>
          <strong>{peso.format(order.total)}</strong>
        </div>
        <PaymentOptions />
        <div className="to-shipping-excluded">
          <strong>Shipping is not included in this total.</strong>
          <p>
            To:CC will contact you through Instagram at the username provided to
            confirm the shipping fee and final delivery details.
          </p>
        </div>
        <a
          className="to-primary"
          style={{ display: "block", textAlign: "center" }}
          href={`mailto:your-email@gmail.com?subject=${subject}&body=${body}`}
        >
          Send proof of payment
        </a>
        <p className="to-proof-example">
          Use subject:{" "}
          <strong>Proof of payment for order {order.orderNumber}</strong>
          <br />
          Placeholder recipient: your-email@gmail.com
        </p>
        {order.status === "awaiting_payment" ? (
          <button
            className="to-secondary"
            type="button"
            onClick={() => void confirmSent()}
          >
            I emailed my proof
          </button>
        ) : (
          <p className="to-order-sent">
            Payment marked as sent. We’ll review it next.
          </p>
        )}
        <a className="to-account-orders-link" href="account.html">
          View My Orders →
        </a>
      </div>
    );
  }

  if (!lines.length)
    return (
      <div className="to-panel to-empty">
        <h2>Your bag is quiet.</h2>
        <p>Discover the Comfort Capsule collection and choose your piece.</p>
        <a
          className="to-text-button"
          href="category.html?collection=comfort-capsule"
        >
          Continue shopping
        </a>
      </div>
    );
  return (
    <form onSubmit={submit} className="to-checkout-grid">
      <div className="to-panel">
        <h2>Your selection</h2>
        {lines.map((line, index) => (
          <article
            className="to-cart-item"
            key={`${line.productId}-${line.color}-${line.size}`}
          >
            <img src={line.product.colors[line.color].images[0]} alt="" />
            <div>
              <h3>{line.product.name}</h3>
              <p className="to-cart-meta">
                {line.color} · {line.size}
              </p>
              <div className="to-qty">
                <button
                  type="button"
                  onClick={() => changeQuantity(index, -1)}
                  aria-label="Decrease quantity"
                >
                  −
                </button>
                <span>{line.quantity}</span>
                <button
                  type="button"
                  onClick={() => changeQuantity(index, 1)}
                  aria-label="Increase quantity"
                >
                  +
                </button>
                <button
                  type="button"
                  className="to-text-button"
                  onClick={() => changeQuantity(index, -line.quantity)}
                >
                  Remove
                </button>
              </div>
            </div>
            <strong className="to-cart-price">
              {peso.format(line.product.priceValue * line.quantity)}
            </strong>
          </article>
        ))}
        <h2 style={{ marginTop: "2.5rem" }}>Delivery details</h2>
        <div className="to-form-grid">
          <label className="to-field">
            Full name
            <input name="fullName" required autoComplete="name" />
          </label>
          <label className="to-field">
            Phone
            <input name="phone" required autoComplete="tel" />
          </label>
        </div>
        <label className="to-field">
          Address
          <textarea
            name="address"
            rows="3"
            required
            autoComplete="street-address"
          />
        </label>
        <div className="to-form-grid">
          <label className="to-field">
            City
            <input name="city" required autoComplete="address-level2" />
          </label>
          <label className="to-field">
            Postal code
            <input name="postalCode" required autoComplete="postal-code" />
          </label>
        </div>
        <label className="to-field">
          Instagram username
          <input name="instagram" required placeholder="@username" />
        </label>
        <h2 style={{ marginTop: "2rem" }}>Payment</h2>
        <p style={{ fontSize: ".78rem", color: "#777" }}>
          Open either option to view its account and QR details. You don’t need
          to select one.
        </p>
        <PaymentOptions />
        <p className="to-proof-placement">
          Your order number and Send proof of payment button will appear after
          you continue.
        </p>
      </div>
      <aside className="to-panel">
        <h2>Order summary</h2>
        <div className="to-summary-row">
          <span>Subtotal</span>
          <span>{peso.format(subtotal)}</span>
        </div>
        <div className="to-summary-row">
          <span>Offers</span>
          <span>{discount ? `−${peso.format(discount)}` : "—"}</span>
        </div>
        <div className="to-summary-row">
          <span>Shipping</span>
          <span>Excluded</span>
        </div>
        <div className="to-summary-row to-summary-total">
          <span>Total</span>
          <span>{peso.format(quote?.total ?? subtotal - discount)}</span>
        </div>
        <p className="to-notice" style={{ margin: "1.25rem 0" }}>
          Shipping is excluded. We’ll contact you through Instagram to confirm
          the fee and delivery details.
        </p>
        <button className="to-primary" disabled={busy || !quote}>
          {busy ? "Creating order…" : "Continue to payment"}
        </button>
      </aside>
    </form>
  );
}

function Checkout() {
  const [products, setProducts] = useState(null);
  const [cart, setCart] = useState(readCart());
  useEffect(() => {
    fetch("/products.json")
      .then((r) => r.json())
      .then(setProducts);
  }, []);
  if (!products)
    return <div className="to-panel">Preparing your selection…</div>;
  return (
    <>
      <AuthLoading>
        <div className="to-panel">Checking your account…</div>
      </AuthLoading>
      <Unauthenticated>
        <SignInInline />
      </Unauthenticated>
      <Authenticated>
        <CheckoutForm products={products} cart={cart} setCart={setCart} />
      </Authenticated>
    </>
  );
}

const customerStages = [
  "payment_sent",
  "payment_approved",
  "contacted_for_shipping",
  "completed",
];
const stageLabels = {
  awaiting_payment: "Awaiting proof",
  payment_sent: "Payment sent",
  payment_approved: "Payment approved",
  contacted_for_shipping: "Contacted for shipping",
  completed: "Completed",
  cancelled: "Cancelled",
};
function ReviewForm({ orderId, item, defaultName }) {
  const client = useConvex();
  const [open, setOpen] = useState(false);
  const [message, setMessage] = useState("");
  const [sent, setSent] = useState(false);
  async function submit(event) {
    event.preventDefault();
    setMessage("Publishing…");
    const fd = new FormData(event.currentTarget);
    try {
      const ratingValue = fd.get("rating");
      await client.mutation(submitReviewRef, {
        orderId,
        productId: item.productId,
        name: fd.get("name"),
        rating: ratingValue ? Number(ratingValue) : undefined,
        comment: fd.get("comment"),
      });
      setSent(true);
      setMessage("Thank you — your verified review is live.");
    } catch (error) {
      setMessage(
        error?.data ??
          "We couldn’t publish this review. It may already have been submitted.",
      );
    }
  }
  if (sent) return <p className="to-review-success">{message}</p>;
  return (
    <div className="to-order-review">
      <button type="button" onClick={() => setOpen(!open)}>
        {open ? "Close review" : `Review ${item.name}`}
      </button>
      {open && (
        <form onSubmit={submit}>
          <div className="to-form-grid">
            <label className="to-field">
              Display name
              <input
                name="name"
                required
                maxLength="40"
                defaultValue={defaultName}
              />
            </label>
            <label className="to-field">
              Rating
              <select name="rating" defaultValue="5">
                <option value="">No star rating</option>
                <option value="5">5 — Love it</option>
                <option value="4">4 — Very good</option>
                <option value="3">3 — Good</option>
                <option value="2">2 — Could be better</option>
                <option value="1">1 — Not for me</option>
              </select>
            </label>
          </div>
          <label className="to-field">
            Your review
            <textarea
              name="comment"
              minLength="5"
              maxLength="600"
              rows="4"
              required
              placeholder="How did it fit and feel?"
            />
          </label>
          <button className="to-primary">Publish review</button>
          {message && (
            <p className="to-profile-saved" role="status">
              {message}
            </p>
          )}
        </form>
      )}
    </div>
  );
}
function AccountDesk() {
  const profile = useQuery(myProfileRef, {});
  const orders = useQuery(myOrdersRef, {});
  const client = useConvex();
  const [saved, setSaved] = useState("");
  if (profile === undefined || orders === undefined)
    return <div className="to-panel">Loading your account…</div>;
  async function save(event) {
    event.preventDefault();
    setSaved("Saving…");
    const fd = new FormData(event.currentTarget);
    try {
      await client.mutation(saveProfileRef, {
        displayName: fd.get("displayName"),
        phone: fd.get("phone"),
        shippingAddress: fd.get("shippingAddress"),
        instagram: fd.get("instagram"),
      });
      setSaved("Details saved.");
    } catch {
      setSaved("We couldn’t save your details.");
    }
  }
  async function cancelOrder(orderId) {
    if (!window.confirm("Cancel this order? Reserved stock will be returned."))
      return;
    try {
      await client.mutation(cancelMyOrderRef, { orderId });
    } catch {
      window.alert(
        "This order can no longer be cancelled online. Please contact To:CC.",
      );
    }
  }
  return (
    <div className="to-account-page-grid">
      <section className="to-panel">
        <p className="to-eyebrow">Your details</p>
        <h2>Profile</h2>
        <form onSubmit={save}>
          <label className="to-field">
            Name
            <input
              name="displayName"
              defaultValue={profile?.displayName ?? ""}
            />
          </label>
          <label className="to-field">
            Phone
            <input name="phone" defaultValue={profile?.phone ?? ""} />
          </label>
          <label className="to-field">
            Instagram username
            <input
              name="instagram"
              placeholder="@username"
              defaultValue={profile?.instagram ?? ""}
            />
          </label>
          <label className="to-field">
            Default shipping address
            <textarea
              name="shippingAddress"
              rows="4"
              defaultValue={profile?.shippingAddress ?? ""}
            />
          </label>
          <button className="to-primary">Save details</button>
          {saved && (
            <p className="to-profile-saved" role="status">
              {saved}
            </p>
          )}
        </form>
      </section>
      <section>
        <div className="to-account-section-heading">
          <p className="to-eyebrow">Order history</p>
          <h2>My orders</h2>
        </div>
        {orders.length === 0 ? (
          <div className="to-panel to-empty">
            You haven’t placed an order yet.
          </div>
        ) : (
          orders.map((order) => {
            const active = customerStages.indexOf(order.status);
            return (
              <article
                className={`to-customer-order ${order.status === "cancelled" ? "is-cancelled" : ""}`}
                key={order._id}
              >
                <div className="to-customer-order-head">
                  <div>
                    <strong>{order.orderNumber}</strong>
                    <span>
                      {new Date(order.createdAt).toLocaleDateString("en-PH", {
                        year: "numeric",
                        month: "short",
                        day: "numeric",
                      })}
                    </span>
                  </div>
                  <strong>{peso.format(order.total)}</strong>
                </div>
                {order.status !== "cancelled" &&
                  order.status !== "completed" && (
                    <div className="to-order-timeline">
                      {customerStages.map((stage, index) => (
                        <div
                          className={index <= active ? "is-complete" : ""}
                          key={stage}
                        >
                          <i></i>
                          <span>{stageLabels[stage]}</span>
                        </div>
                      ))}
                    </div>
                  )}
                <p className="to-order-status-copy">
                  Current status:{" "}
                  <strong>
                    {stageLabels[order.status] ??
                      order.status.replaceAll("_", " ")}
                  </strong>
                </p>
                <div className="to-order-items">
                  {order.items.map((item) => (
                    <span key={`${item.productId}-${item.color}-${item.size}`}>
                      {item.name} · {item.color} · {item.size} × {item.quantity}
                    </span>
                  ))}
                </div>
                {order.status === "awaiting_payment" && (
                  <button
                    className="to-cancel-order"
                    type="button"
                    onClick={() => void cancelOrder(order._id)}
                  >
                    Cancel order
                  </button>
                )}
                {order.status !== "awaiting_payment" &&
                  order.status !== "cancelled" &&
                  order.status !== "completed" && (
                    <p className="to-cancel-help">
                      Need to cancel? Contact To:CC because this order has
                      already entered payment review.
                    </p>
                  )}
                {order.status === "completed" && (
                  <div className="to-order-review-list">
                    {[
                      ...new Map(
                        order.items.map((item) => [item.productId, item]),
                      ).values(),
                    ].map((item) => (
                      <ReviewForm
                        key={item.productId}
                        orderId={order._id}
                        item={item}
                        defaultName={profile?.displayName ?? ""}
                      />
                    ))}
                  </div>
                )}
              </article>
            );
          })
        )}
      </section>
    </div>
  );
}
function AccountPage() {
  return (
    <>
      <AuthLoading>
        <div className="to-panel">Checking your account…</div>
      </AuthLoading>
      <Unauthenticated>
        <SignInInline />
      </Unauthenticated>
      <Authenticated>
        <AccountDesk />
      </Authenticated>
    </>
  );
}

const statuses = [
  "payment_sent",
  "payment_approved",
  "contacted_for_shipping",
  "completed",
  "cancelled",
];
function AdminDesk() {
  const orders = useQuery(adminOrdersRef, {});
  const subscribers = useQuery(adminSubscribersRef, {});
  const reviews = useQuery(adminReviewsRef, {});
  const inventory = useQuery(adminInventoryRef, {});
  const productLabels = useQuery(adminProductLabelsRef, {});
  const client = useConvex();
  const [activeTab, setActiveTab] = useState("orders");
  const [orderView, setOrderView] = useState("active");
  const [reviewMessage, setReviewMessage] = useState("");
  const [savingSku, setSavingSku] = useState("");
  const [editingSku, setEditingSku] = useState("");
  const [savedSku, setSavedSku] = useState("");
  const [savingLabels, setSavingLabels] = useState("");
  const [savedLabels, setSavedLabels] = useState("");
  useEffect(() => {
    void client.mutation(adminSeedReviewsRef, {}).catch(() => {});
  }, [client]);
  async function saveStock(row, event) {
    const stock = Number(new FormData(event.currentTarget).get("stock"));
    setSavingSku(row.sku);
    setSavedSku("");
    try {
      await client.mutation(setStockRef, {
        productId: row.productId,
        color: row.color,
        size: row.size,
        stock,
      });
      setEditingSku("");
      setSavedSku(row.sku);
      window.setTimeout(
        () => setSavedSku((current) => (current === row.sku ? "" : current)),
        1800,
      );
    } catch {
      window.alert("Stock was not saved. Please try again.");
    } finally {
      setSavingSku("");
    }
  }
  async function saveLabels(productId, event) {
    event.preventDefault();
    const labels = new FormData(event.currentTarget).getAll("labels");
    setSavingLabels(productId);
    setSavedLabels("");
    try {
      await client.mutation(setProductLabelsRef, { productId, labels });
      setSavedLabels(productId);
      window.setTimeout(
        () =>
          setSavedLabels((current) => (current === productId ? "" : current)),
        1800,
      );
    } catch {
      window.alert("Labels were not saved. Please try again.");
    } finally {
      setSavingLabels("");
    }
  }
  async function addAdminReview(event) {
    event.preventDefault();
    const form = event.currentTarget;
    const data = new FormData(form);
    const rating = data.get("rating");
    setReviewMessage("Adding review…");
    try {
      await client.mutation(adminAddReviewRef, {
        productId: data.get("productId"),
        name: data.get("name"),
        color: data.get("color"),
        ...(rating ? { rating: Number(rating) } : {}),
        comment: data.get("comment"),
      });
      form.reset();
      setReviewMessage("Review added ✓");
    } catch (error) {
      setReviewMessage(
        error?.data ?? "Review was not added. Please check the fields.",
      );
    }
  }
  async function deleteAdminReview(review) {
    if (!window.confirm(`Delete ${review.name}'s review?`)) return;
    if (
      !window.confirm(
        "This permanently removes the review. Are you absolutely sure?",
      )
    )
      return;
    try {
      await client.mutation(adminDeleteReviewRef, { reviewId: review._id });
    } catch {
      window.alert("The review could not be deleted. Please try again.");
    }
  }
  if (
    orders === undefined ||
    subscribers === undefined ||
    reviews === undefined ||
    inventory === undefined ||
    productLabels === undefined
  )
    return <div className="to-panel">Loading store data…</div>;
  const labelMap = Object.fromEntries(
    productLabels.map((row) => [row.productId, row.labels]),
  );
  const products = Object.values(
    inventory.reduce((groups, row) => {
      if (!groups[row.productId])
        groups[row.productId] = {
          productId: row.productId,
          rows: [],
          labels: labelMap[row.productId] ?? [],
        };
      groups[row.productId].rows.push(row);
      return groups;
    }, {}),
  );
  const filteredOrders = orders.filter((order) =>
    orderView === "active"
      ? order.status !== "completed" && order.status !== "cancelled"
      : order.status === orderView,
  );
  return (
    <div>
      <nav className="to-admin-tabs" aria-label="Administration sections">
        {[
          ["orders", "Orders", orders.length],
          ["inventory", "Inventory", products.length],
          ["reviews", "Reviews", reviews.length],
          ["subscribers", "CC Me In", subscribers.length],
        ].map(([id, label, count]) => (
          <button
            key={id}
            data-active={activeTab === id}
            onClick={() => setActiveTab(id)}
          >
            <span>{label}</span>
            <small>{count}</small>
          </button>
        ))}
      </nav>
      {activeTab === "inventory" && (
        <section className="to-admin-section">
          <div className="to-admin-section-heading">
            <div>
              <p className="to-eyebrow">Private stock controls</p>
              <h2>Inventory</h2>
            </div>
            <span>{products.length} products</span>
          </div>
          <div className="to-inventory-products">
            {products.map((product, index) => (
              <details key={product.productId} open={index === 0}>
                <summary>
                  <div>
                    <strong>
                      {product.productId.startsWith("cloud-touch-")
                        ? product.productId.replace(
                            "cloud-touch-",
                            "cloud-touch ",
                          )
                        : product.productId.replaceAll("-", " ")}
                    </strong>
                    <span>
                      {product.rows.reduce((sum, row) => sum + row.stock, 0)}{" "}
                      units total
                    </span>
                  </div>
                  <i aria-hidden="true"></i>
                </summary>
                <form
                  className="to-admin-label-editor"
                  onSubmit={(event) =>
                    void saveLabels(product.productId, event)
                  }
                >
                  <div>
                    <strong>Product labels</strong>
                    <span>Shown above the product name</span>
                  </div>
                  <label>
                    <input
                      type="checkbox"
                      name="labels"
                      value="new"
                      defaultChecked={product.labels.includes("new")}
                    />
                    <span>New</span>
                  </label>
                  <label>
                    <input
                      type="checkbox"
                      name="labels"
                      value="best_seller"
                      defaultChecked={product.labels.includes("best_seller")}
                    />
                    <span>Best seller</span>
                  </label>
                  <label>
                    <input
                      type="checkbox"
                      name="labels"
                      value="back_in_stock"
                      defaultChecked={product.labels.includes("back_in_stock")}
                    />
                    <span>Back in stock</span>
                  </label>
                  <button disabled={savingLabels === product.productId}>
                    {savingLabels === product.productId
                      ? "Saving…"
                      : savedLabels === product.productId
                        ? "Saved ✓"
                        : "Save labels"}
                  </button>
                </form>
                <div className="to-inventory-variants">
                  {Object.entries(
                    product.rows.reduce((colors, row) => {
                      (colors[row.color] ??= []).push(row);
                      return colors;
                    }, {}),
                  ).map(([color, rows]) => (
                    <section key={color}>
                      <h3>{color}</h3>
                      <div>
                        {rows.map((row) => {
                          const editing = editingSku === row.sku;
                          return (
                            <form
                              className={editing ? "is-editing" : ""}
                              key={row.sku}
                              onSubmit={(event) => {
                                event.preventDefault();
                                void saveStock(row, event);
                              }}
                            >
                              <label>
                                <span>Size {row.size}</span>
                                <small>
                                  {savedSku === row.sku
                                    ? "Saved to Convex ✓"
                                    : "Current stock"}
                                </small>
                              </label>
                              <input
                                key={`${row.sku}-${row.stock}`}
                                name="stock"
                                type="number"
                                min="0"
                                max="999"
                                step="1"
                                defaultValue={row.stock}
                                readOnly={!editing}
                                onClick={() => {
                                  if (!editing) {
                                    setEditingSku(row.sku);
                                    setSavedSku("");
                                  }
                                }}
                                aria-label={`Stock for ${row.sku}`}
                              />
                              {editing ? (
                                <button
                                  type="submit"
                                  disabled={savingSku === row.sku}
                                >
                                  {savingSku === row.sku ? "Saving…" : "Save"}
                                </button>
                              ) : (
                                <button
                                  type="button"
                                  onClick={() => {
                                    setEditingSku(row.sku);
                                    setSavedSku("");
                                  }}
                                >
                                  Edit
                                </button>
                              )}
                            </form>
                          );
                        })}
                      </div>
                    </section>
                  ))}
                </div>
              </details>
            ))}
          </div>
        </section>
      )}
      {activeTab === "subscribers" && (
        <section className="to-admin-section">
          <div className="to-admin-section-heading">
            <div>
              <p className="to-eyebrow">Private mailing list</p>
              <h2>CC Me In</h2>
            </div>
            <span>{subscribers.length} subscribers</span>
          </div>
          {subscribers.length === 0 ? (
            <div className="to-panel to-empty">No subscribers yet.</div>
          ) : (
            <div className="to-subscriber-list">
              {subscribers.map((subscriber) => (
                <div key={subscriber._id}>
                  <span>{subscriber.email}</span>
                  <time
                    dateTime={new Date(subscriber.subscribedAt).toISOString()}
                  >
                    {new Date(subscriber.subscribedAt).toLocaleDateString(
                      "en-PH",
                      { year: "numeric", month: "short", day: "numeric" },
                    )}
                  </time>
                </div>
              ))}
            </div>
          )}
        </section>
      )}
      {activeTab === "reviews" && (
        <section className="to-admin-section">
          <div className="to-admin-section-heading">
            <div>
              <p className="to-eyebrow">Customer comments</p>
              <h2>Reviews</h2>
            </div>
            <span>{reviews.length} reviews</span>
          </div>
          <form
            className="to-admin-review-form"
            onSubmit={(event) => void addAdminReview(event)}
          >
            <div className="to-form-grid">
              <label className="to-field">
                <span>Product</span>
                <select name="productId" required>
                  {products.map((product) => (
                    <option key={product.productId} value={product.productId}>
                      {product.productId.replaceAll("-", " ")}
                    </option>
                  ))}
                </select>
              </label>
              <label className="to-field">
                <span>Name</span>
                <input name="name" maxLength="40" required />
              </label>
              <label className="to-field">
                <span>Color</span>
                <input name="color" maxLength="30" required />
              </label>
              <label className="to-field">
                <span>Stars (optional)</span>
                <select name="rating">
                  <option value="">No star rating</option>
                  {[5, 4, 3, 2, 1].map((rating) => (
                    <option key={rating} value={rating}>
                      {rating} stars
                    </option>
                  ))}
                </select>
              </label>
            </div>
            <label className="to-field">
              <span>Review</span>
              <textarea
                name="comment"
                rows="3"
                minLength="2"
                maxLength="600"
                required
              />
            </label>
            <div className="to-admin-review-form-actions">
              <button type="submit">Add review</button>
              <span>{reviewMessage}</span>
            </div>
          </form>
          {reviews.length === 0 ? (
            <div className="to-panel to-empty">No customer reviews yet.</div>
          ) : (
            <div className="to-admin-review-list">
              {reviews.map((review) => (
                <article key={review._id}>
                  <div>
                    <strong>{review.name}</strong>
                    <span>
                      {review.productId.replaceAll("-", " ")} · {review.color}
                    </span>
                  </div>
                  {Number.isFinite(review.rating) ? (
                    <span className="to-admin-review-stars">
                      {"★".repeat(review.rating)}
                      {"☆".repeat(5 - review.rating)}
                    </span>
                  ) : (
                    <span className="to-admin-review-unrated">
                      No star rating
                    </span>
                  )}
                  <p>{review.comment}</p>
                  <time>
                    {new Date(review.createdAt).toLocaleDateString("en-PH", {
                      year: "numeric",
                      month: "short",
                      day: "numeric",
                    })}
                  </time>
                  <button
                    className="to-review-delete"
                    type="button"
                    onClick={() => void deleteAdminReview(review)}
                  >
                    Delete review
                  </button>
                </article>
              ))}
            </div>
          )}
        </section>
      )}
      {activeTab === "orders" && (
        <section className="to-admin-section">
          <div className="to-admin-section-heading">
            <div>
              <p className="to-eyebrow">Order workflow</p>
              <h2>Orders</h2>
            </div>
            <span>{filteredOrders.length} shown</span>
          </div>
          <div className="to-order-view-tabs">
            {[
              ["active", "Active orders"],
              ["completed", "Completed"],
              ["cancelled", "Cancelled"],
            ].map(([id, label]) => (
              <button
                type="button"
                key={id}
                data-active={orderView === id}
                onClick={() => setOrderView(id)}
              >
                {label}
              </button>
            ))}
          </div>
          {filteredOrders.length === 0 ? (
            <div className="to-panel to-empty">No {orderView} orders.</div>
          ) : (
            filteredOrders.map((order) => (
              <article
                className={`to-admin-order ${order.status === "cancelled" || order.status === "completed" ? "is-archived" : ""}`}
                key={order._id}
              >
                <div className="to-admin-head">
                  <div>
                    <strong>{order.orderNumber}</strong>
                    <p className="to-cart-meta">
                      {order.shipping.fullName} · {order.shipping.city} ·{" "}
                      {order.paymentMethod.replace("_", " ")}
                    </p>
                  </div>
                  <span className="to-status">
                    {order.status.replaceAll("_", " ")}
                  </span>
                  <strong>{peso.format(order.total)}</strong>
                </div>
                <p style={{ fontSize: ".78rem" }}>
                  {order.items
                    .map(
                      (i) =>
                        `${i.name} / ${i.color} / ${i.size} × ${i.quantity}`,
                    )
                    .join(" · ")}
                </p>
                {order.status !== "cancelled" && (
                  <div className="to-status-actions">
                    {statuses.map((status) => (
                      <button
                        key={status}
                        data-active={order.status === status}
                        data-cancel={status === "cancelled"}
                        disabled={order.status === status}
                        onClick={() =>
                          client.mutation(updateStatusRef, {
                            orderId: order._id,
                            status,
                          })
                        }
                      >
                        {order.status === status ? "Current · " : ""}
                        {status.replaceAll("_", " ")}
                      </button>
                    ))}
                  </div>
                )}
              </article>
            ))
          )}
        </section>
      )}
    </div>
  );
}
function AdminGate() {
  const allowed = useQuery(adminCheckRef, {});
  useEffect(() => {
    if (allowed === false) window.location.replace("index.html");
  }, [allowed]);
  if (allowed === undefined)
    return <div className="to-panel">Checking admin access…</div>;
  if (!allowed)
    return <div className="to-panel">Returning you to the shop…</div>;
  return <AdminDesk />;
}
function Admin() {
  return (
    <>
      <AuthLoading>
        <div className="to-panel">Checking access…</div>
      </AuthLoading>
      <Unauthenticated>
        <SignInInline />
      </Unauthenticated>
      <Authenticated>
        <AdminGate />
      </Authenticated>
    </>
  );
}

function mount(id, component) {
  const root = document.getElementById(id);
  if (!root) return;
  if (!deploymentUrl) {
    root.innerHTML =
      '<p class="to-notice">Connect the Convex deployment to activate this section.</p>';
    return;
  }
  const client = new ConvexReactClient(deploymentUrl);
  createRoot(root).render(
    <ConvexAuthProvider client={client}>{component}</ConvexAuthProvider>,
  );
}
document.querySelectorAll("[data-newsletter-root]").forEach((root) => {
  const client = deploymentUrl ? new ConvexReactClient(deploymentUrl) : null;
  createRoot(root).render(<Newsletter client={client} />);
});
document.querySelectorAll("[data-community-signup-root]").forEach((root) => {
  const client = deploymentUrl ? new ConvexReactClient(deploymentUrl) : null;
  createRoot(root).render(<CommunitySignup client={client} />);
});
mount("checkout-root", <Checkout />);
mount("admin-root", <Admin />);
mount("account-page-root", <AccountPage />);

const siteHeader = document.querySelector(".to-site-header");
const menuButton = document.getElementById("menuBtn");
const mobileMenu = document.getElementById("mobileMenu");
function updateHeader() {
  if (siteHeader && !siteHeader.classList.contains("is-solid"))
    siteHeader.classList.toggle("is-scrolled", window.scrollY > 24);
}
updateHeader();
window.addEventListener("scroll", updateHeader, { passive: true });
menuButton?.addEventListener("click", () => {
  const open = menuButton.getAttribute("aria-expanded") !== "true";
  menuButton.setAttribute("aria-expanded", String(open));
  menuButton.setAttribute("aria-label", open ? "Close menu" : "Open menu");
  mobileMenu?.classList.toggle("is-open", open);
  mobileMenu?.setAttribute("aria-hidden", String(!open));
});
