// Dedicated Support page.
//
// Reseller-portal-only — reached from the "Raise a ticket" / "My tickets"
// cards on ResellerPortalDashboard, or the persistent top nav on
// ResellerShell (see reseller-shell.jsx). Not linked anywhere on the
// public marketing site. Gated the same way the dashboard itself is
// gated: checks /api/portal/me on mount and bounces to reseller-login if
// there's no valid session, so a stale bookmark or direct nav can't
// reach the form while logged out.
//
// Renders entirely inside <ResellerShell> — dark portal chrome, same as
// every other reseller-portal page — instead of the old light-themed
// public-marketing-site hero/Eyebrow treatment. Which of the two tabs
// ("raise" / "my-tickets") is showing is a CONTROLLED prop (`activeTab`)
// driven by App()'s `supportTab` state (see app.jsx), not local state —
// this is what lets ResellerShell's persistent nav (and the dashboard's
// two Support buttons) land directly on the right tab.
//
// Two tabs: "Raise a ticket" (the form, backed by a real API — POST
// /api/portal/tickets persists the ticket so Solo staff can see and
// reply to it in the admin area, see admin-tickets-page.jsx) and
// "My tickets" (GET /api/portal/tickets — list + a detail/thread view
// with a reply box, GET/POST /api/portal/tickets/:id[/messages]).
//
// Form mirrors the SupportTicketForm pattern from contact-page.jsx but
// extended with: multi-file uploads, region selector, phone number field,
// and region-specific phone number reference cards on the side. NOTE:
// attachments aren't uploaded/stored by the backend yet (no R2 wiring
// for tickets) — selected files are listed for the reseller's own
// reference but not sent; the confirmation screen tells them to email
// attachments separately if needed.

// The only email address the site shows/sends to, per direct
// instruction. Fallback only; real routing is
// SOLO_BACKEND.inbox.support in solo-backend.js.
const SUPPORT_INBOX = "contactus@solosecure.group";

// Regions Solo operates across. Used by the form selector and the
// reference card grid.
const SUPPORT_REGIONS = [
  {
    region:    "United Kingdom",
    short:     "UK",
    // TODO: replace placeholder with real support number when issued
    phone:     "+44 (0) 000 000 0000",
    note:      "UK HQ + production. Mon–Fri 08:00–18:00 BST.",
  },
  {
    region:    "European Union",
    short:     "EU",
    phone:     "+48 00 000 0000",
    note:      "Poland factory + EU support. Mon–Fri 08:00–17:00 CET.",
  },
  {
    region:    "North America",
    short:     "NA",
    phone:     "+1 (561) 293-7022",
    note:      "Wellington FL operations. Mon–Fri 08:00–17:00 EST.",
  },
  {
    region:    "Middle East / GCC",
    short:     "ME",
    phone:     "+971 0 000 0000",
    note:      "UAE office. Sun–Thu 09:00–18:00 GST.",
  },
];

// `activeTab`/`onTabChange`: controlled from App() (see app.jsx's
// `supportTab` state) so ResellerShell's persistent nav — and
// ResellerPortalDashboard's two Support buttons — can target a specific
// tab via onNavigate("support", { tab: "..." }) without this page ever
// resetting back to a hardcoded default on its own.
function SupportPage({ onNavigate, activeTab, onTabChange }) {
  // idle → checking-session (on mount) → ready. Mirrors the same
  // /api/portal/me check used by ResellerLoginPage / ResellerPortalDashboard
  // — this page only exists inside the authenticated reseller portal now,
  // so a logged-out visitor (stale bookmark, direct nav) gets bounced
  // straight to reseller-login instead of ever seeing the form.
  const [status, setStatus] = useState("checking-session");
  const tab = activeTab || "raise"; // raise | my-tickets
  const [state, setState] = useState({});
  const [files, setFiles] = useState([]);
  const [submitted, setSubmitted] = useState(false);
  const [submitError, setSubmitError] = useState("");
  const [submitting, setSubmitting] = useState(false);
  // Reference comes back from the backend on successful creation (see
  // POST /api/portal/tickets) so the user can quote it back if they
  // follow up, and so it matches the ticket_number Solo staff see too.
  const [ticketRef, setTicketRef] = useState("");
  // Who's raising it — name/email/company are shown read-only, sourced
  // entirely from the signed-in session, never editable free text. The
  // backend independently re-derives name/email from the session too
  // (see POST /api/portal/tickets), so even a tampered request can't
  // raise a ticket claiming to be someone else.
  const [me, setMe] = useState({ name: "", email: "", company: "", companyId: null, isSoloStaff: false });
  // The reseller's OWN assets only — populated from GET /api/portal/assets,
  // which is itself scoped server-side to the signed-in user's company.
  // This is what the "Asset / unit" dropdown below is built from, so a
  // reseller physically cannot select — let alone free-type — another
  // company's serial number or unit.
  const [assets, setAssets] = useState({ status: "loading", items: [] });
  // Solo-staff "view as company" switcher — see reseller-shell.jsx +
  // reseller-portal-dashboard.jsx for the same pattern; kept here too so
  // the switcher (and correctly-scoped assets/tickets) stays available
  // no matter which portal page a Solo-staff member lands on.
  const [companies, setCompanies] = useState([]);

  const loadAssets = () => {
    fetch("/api/portal/assets", { credentials: "same-origin" })
      .then((r) => (r.ok ? r.json() : { assets: [] }))
      .then((data) => setAssets({ status: "ready", items: data.assets || [] }))
      .catch(() => setAssets({ status: "ready", items: [] }));
  };

  const loadMe = (onDone) => {
    fetch("/api/portal/me", { credentials: "same-origin" })
      .then((r) => (r.ok ? r.json() : null))
      .then((data) => {
        if (!data?.user) { onNavigate("reseller-login"); return; }
        setMe({
          name: data.user.name || "",
          email: data.user.email || "",
          company: data.company?.name || "",
          companyId: data.company?.id || null,
          isSoloStaff: !!data.isSoloStaff,
        });
        setStatus("ready");
        if (data.isSoloStaff) {
          fetch("/api/portal/companies", { credentials: "same-origin" })
            .then((r) => (r.ok ? r.json() : { companies: [] }))
            .then((d) => setCompanies(d.companies || []))
            .catch(() => setCompanies([]));
        }
        if (onDone) onDone();
      })
      .catch(() => { onNavigate("reseller-login"); });
  };

  const handleSwitchCompany = (companyId) => {
    fetch("/api/portal/switch-company", {
      method: "POST", credentials: "same-origin",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ companyId }),
    })
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then(() => { loadMe(() => loadAssets()); })
      .catch(() => { /* switch failed silently — page stays on current company */ });
  };

  useEffect(() => {
    loadMe();
    loadAssets();
  }, []); // eslint-disable-line react-hooks/exhaustive-deps -- mount-only

  const set = (k, v) => setState((s) => ({ ...s, [k]: v }));

  const handleFiles = (e) => {
    const incoming = Array.from(e.target.files || []);
    // Cap at 10 total to keep the form sane.
    setFiles((prev) => [...prev, ...incoming].slice(0, 10));
    // Reset the input so the same file can be picked again if removed.
    e.target.value = "";
  };

  const removeFile = (idx) => {
    setFiles((prev) => prev.filter((_, i) => i !== idx));
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setSubmitError("");
    setSubmitting(true);
    try {
      const res = await fetch("/api/portal/tickets", {
        method: "POST", credentials: "same-origin",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          severity:    state.severity || "Standard",
          ticketType:  state.ticketType,
          region:      state.region,
          // assetUnitId, not free-text customerRef — the backend
          // re-checks this id belongs to the signed-in reseller's own
          // company before accepting it (see POST /api/portal/tickets).
          assetUnitId: state.assetUnitId || null,
          phone:       state.phone,
          description: state.description,
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        setSubmitError(data.error || "Something went wrong — please try again.");
        setSubmitting(false);
        return;
      }
      setTicketRef(data.ticketNumber);
      setSubmitted(true);
    } catch {
      setSubmitError("Couldn't reach the server. Check your connection and try again.");
    } finally {
      setSubmitting(false);
    }
  };

  if (status === "checking-session") {
    // Avoid flashing the form for the instant it takes to check the
    // session — same pattern as ResellerLoginPage.
    return <section style={{ background: "#000", minHeight: "calc(100vh - 88px)" }} />;
  }

  if (submitted) {
    const inbox = window.SOLO_BACKEND?.inbox?.support || SUPPORT_INBOX;
    return (
      <ResellerShell
        page="support" activeTab={tab} onNavigate={onNavigate}
        userName={me.name} companyName={me.company}
        isSoloStaff={me.isSoloStaff} companies={companies}
        currentCompanyId={me.companyId} onSwitchCompany={handleSwitchCompany}
        subtitle="Ticket raised"
      >
        {/* Reference card — front and centre so it's the first thing the user sees */}
        <div style={{
          background: "rgba(255,255,255,0.06)", border: "1px solid rgba(255,255,255,0.3)",
          padding: "32px 36px 36px", marginBottom: 36,
          display: "flex", justifyContent: "space-between",
          alignItems: "center", gap: 24, flexWrap: "wrap",
        }}>
          <div>
            <div style={{
              fontFamily: "var(--font-body)", fontSize: 11,
              letterSpacing: "0.22em", textTransform: "uppercase",
              color: "rgba(255,255,255,0.6)", fontWeight: 500,
              marginBottom: 8,
            }}>Your ticket reference</div>
            <div style={{
              fontFamily: "var(--font-display)", fontWeight: 700,
              fontSize: "clamp(28px, 4vw, 44px)", letterSpacing: "0.005em",
              color: "#fff",
            }}>{ticketRef}</div>
          </div>
          <div style={{
            fontFamily: "var(--font-body)", fontSize: 12,
            letterSpacing: "0.18em", textTransform: "uppercase",
            color: "rgba(255,255,255,0.55)", fontWeight: 500,
            textAlign: "right",
          }}>Quote this ref<br />if you follow up</div>
        </div>

        <h2 style={{
          fontFamily: "var(--font-display)", fontWeight: 700,
          fontSize: "clamp(26px, 3.6vw, 38px)", lineHeight: 1.1,
          letterSpacing: "-0.005em", textTransform: "uppercase",
          margin: "0 0 20px", color: "#fff",
        }}>
          Ticket received.
        </h2>
        <p style={{
          fontFamily: "var(--font-body)", fontSize: 15.5,
          lineHeight: 1.6, color: "rgba(255,255,255,0.7)", margin: "0 0 22px",
        }}>
          Solo support has received your ticket and will respond within one working day. Critical tickets are escalated immediately. You'll see any reply from the Solo team on the "My tickets" tab.
        </p>
        {files.length > 0 && (
          <p style={{
            fontFamily: "var(--font-body)", fontSize: 14,
            lineHeight: 1.6, color: "rgba(255,255,255,0.7)",
            background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.16)",
            padding: "16px 20px", marginBottom: 22,
          }}>
            <strong style={{ color: "#fff" }}>{files.length} attachment{files.length === 1 ? "" : "s"}</strong> selected — Solo can't receive files automatically through this form yet. Please email them to <a href={`mailto:${inbox}`} style={{ color: "#fff", textDecoration: "underline" }}>{inbox}</a> quoting <strong style={{ color: "#fff" }}>{ticketRef}</strong>.
          </p>
        )}
        <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
          <ShellButton onClick={() => { setSubmitted(false); setState({}); setFiles([]); setTicketRef(""); }}>
            Raise another ticket
          </ShellButton>
          <ShellButton onClick={() => { setSubmitted(false); setState({}); setFiles([]); setTicketRef(""); if (onTabChange) onTabChange("my-tickets"); }}>
            View my tickets
          </ShellButton>
          <ShellButton onClick={() => onNavigate("portal-dashboard")}>
            Back to portal
          </ShellButton>
        </div>
      </ResellerShell>
    );
  }

  return (
    <ResellerShell
      page="support" activeTab={tab} onNavigate={onNavigate}
      userName={me.name} companyName={me.company}
      isSoloStaff={me.isSoloStaff} companies={companies}
      currentCompanyId={me.companyId} onSwitchCompany={handleSwitchCompany}
      subtitle="Customer support"
      title={tab === "raise" ? "Raise a support ticket." : "My support tickets."}
    >
      <p style={{
        fontFamily: "var(--font-body)", fontSize: 15.5,
        lineHeight: 1.6, color: "rgba(255,255,255,0.65)", margin: "-16px 0 40px", maxWidth: 640,
      }}>
        {tab === "raise"
          ? "Tell us what's going on. Attach photos, drawings or logs if it helps. Solo support will respond within one working day — faster for Critical and High-severity issues."
          : "Every ticket you've raised, with its current status and the full reply thread with the Solo team."}
      </p>

      {tab === "my-tickets" && <MyTicketsPanel />}

      {/* MAIN BODY — form on the left, support reference on the right */}
      {tab === "raise" && (
        <div style={{
          display: "grid", gridTemplateColumns: "minmax(0, 1.6fr) minmax(0, 1fr)",
          gap: 40, alignItems: "start",
        }}>
          {/* ───── Form ───── */}
          <form onSubmit={handleSubmit} style={{
            background: "rgba(255,255,255,0.04)",
            border: "1px solid rgba(255,255,255,0.18)",
            padding: "36px 38px 40px",
          }}>
            {/* Severity — visual prominence at the top because it routes the response */}
            <FieldLabel>Severity *</FieldLabel>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 8, marginBottom: 26 }}>
              {[
                { val: "Critical", body: "Down / unsafe" },
                { val: "High",     body: "Major impact" },
                { val: "Standard", body: "Normal" },
                { val: "Low",      body: "Question" },
              ].map(({ val, body }) => (
                <button
                  key={val}
                  type="button"
                  onClick={() => set("severity", val)}
                  style={{
                    background: state.severity === val ? "#fff" : "rgba(0,0,0,0.4)",
                    color: state.severity === val ? "#000" : "#fff",
                    border: `1px solid ${state.severity === val ? "#fff" : "rgba(255,255,255,0.2)"}`,
                    padding: "16px 10px 18px",
                    cursor: "pointer",
                    fontFamily: "var(--font-body)",
                    display: "flex", flexDirection: "column",
                    alignItems: "center", justifyContent: "center", gap: 4,
                    transition: "background 120ms",
                  }}>
                  <span style={{
                    fontFamily: "var(--font-display)", fontWeight: 700,
                    fontSize: 14, letterSpacing: "0.04em",
                    textTransform: "uppercase",
                  }}>{val}</span>
                  <span style={{
                    fontFamily: "var(--font-body)", fontSize: 11,
                    letterSpacing: "0.08em", textTransform: "uppercase",
                    opacity: 0.75,
                  }}>{body}</span>
                </button>
              ))}
            </div>

            {/* Ticket type + Region — 2 cols */}
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 18, marginBottom: 18 }}>
              <label style={{ display: "block" }}>
                <FieldLabel>Ticket type *</FieldLabel>
                <select
                  required
                  value={state.ticketType || ""}
                  onChange={(e) => set("ticketType", e.target.value)}
                  style={inputStyle}
                >
                  <option value="">— Select —</option>
                  <option>Fault report</option>
                  <option>Hardware question</option>
                  <option>Firmware / software</option>
                  <option>Connectivity / SIMs</option>
                  <option>Monitoring / alerts</option>
                  <option>Spares / parts</option>
                  <option>Account / billing</option>
                  <option>Other</option>
                </select>
              </label>
              <label style={{ display: "block" }}>
                <FieldLabel>Region *</FieldLabel>
                <select
                  required
                  value={state.region || ""}
                  onChange={(e) => set("region", e.target.value)}
                  style={inputStyle}
                >
                  <option value="">— Select —</option>
                  {SUPPORT_REGIONS.map((r) => (
                    <option key={r.region}>{r.region}</option>
                  ))}
                  <option>Other</option>
                </select>
              </label>
            </div>

            {/* Asset / unit — a dropdown of THIS company's own currently-
                assigned assets only (from GET /api/portal/assets), never
                a free-text field. This is the actual UI enforcement of
                "only raise tickets on your own assets" — you literally
                cannot type a serial number here, only pick one that's
                really yours. Optional, since some ticket types (billing,
                account questions) aren't about a specific unit. The
                backend independently re-checks ownership of whatever id
                is submitted (see POST /api/portal/tickets), so this
                isn't just a client-side restriction. */}
            <label style={{ display: "block", marginBottom: 18 }}>
              <FieldLabel>Asset / unit (optional)</FieldLabel>
              <select
                value={state.assetUnitId || ""}
                onChange={(e) => set("assetUnitId", e.target.value)}
                disabled={assets.status === "loading"}
                style={inputStyle}
                data-testid="support-asset-select"
              >
                <option value="">
                  {assets.status === "loading"
                    ? "Loading your assets…"
                    : assets.items.length === 0
                    ? "No assets on your account — not unit-specific"
                    : "— Not about a specific unit —"}
                </option>
                {assets.items.map((a) => (
                  <option key={a.id} value={a.id}>
                    {a.product_name} · {a.serial_number}
                  </option>
                ))}
              </select>
              {assets.status === "ready" && assets.items.length === 0 && (
                <div style={{
                  fontFamily: "var(--font-body)", fontSize: 11.5,
                  color: "rgba(255,255,255,0.4)", marginTop: 6, lineHeight: 1.5,
                }}>
                  No hardware is assigned to your account yet — you can still raise a ticket, just not against a specific unit.
                </div>
              )}
            </label>

            {/* Who's raising this — read-only, straight from your signed-
                in session. Not editable: a ticket is always raised as
                you, at your own company, never as a free-text identity.
                The backend enforces this too (see POST
                /api/portal/tickets), so this is a display convenience,
                not the actual security boundary. */}
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 18, marginBottom: 18 }}>
              <div>
                <FieldLabel>Raised by</FieldLabel>
                <div style={{ ...inputStyle, color: "rgba(255,255,255,0.75)", cursor: "default" }} data-testid="support-raised-by">
                  {me.name}{me.email ? ` · ${me.email}` : ""}
                </div>
              </div>
              <div>
                <FieldLabel>Company / organisation</FieldLabel>
                <div style={{ ...inputStyle, color: "rgba(255,255,255,0.75)", cursor: "default" }} data-testid="support-raised-by-company">
                  {me.company}
                </div>
              </div>
            </div>

            {/* Phone */}
            <div style={{ display: "grid", gridTemplateColumns: "1fr", gap: 18, marginBottom: 18 }}>
              <label style={{ display: "block" }}>
                <FieldLabel>Phone (optional)</FieldLabel>
                <input
                  type="tel"
                  placeholder="+44 …"
                  value={state.phone || ""}
                  onChange={(e) => set("phone", e.target.value)}
                  style={inputStyle}
                />
              </label>
            </div>

            {/* Description */}
            <label style={{ display: "block", marginBottom: 20 }}>
              <FieldLabel>Describe the issue *</FieldLabel>
              <textarea
                rows={6}
                required
                placeholder="What's the unit / system doing? When did it start? What have you tried?"
                value={state.description || ""}
                onChange={(e) => set("description", e.target.value)}
                style={{ ...inputStyle, resize: "vertical" }}
              />
            </label>

            {/* File upload — multi, with selected file list */}
            <FieldLabel>Attachments (optional)</FieldLabel>
            <div style={{ marginBottom: 20 }}>
              <input
                type="file"
                id="support-files"
                multiple
                accept=".pdf,.png,.jpg,.jpeg,.heic,.gif,.webp,.doc,.docx,.xls,.xlsx,.txt,.log,.csv,.zip,.mp4,.mov"
                onChange={handleFiles}
                style={{ display: "none" }}
              />
              <label htmlFor="support-files" style={{
                ...inputStyle,
                display: "flex", alignItems: "center", justifyContent: "space-between",
                cursor: "pointer", color: "rgba(255,255,255,0.55)",
                padding: "16px 18px",
              }}>
                <span>
                  {files.length === 0 ? "Choose files…" : `${files.length} file${files.length === 1 ? "" : "s"} selected`}
                </span>
                <span style={{
                  fontFamily: "var(--font-body)", fontSize: 11,
                  letterSpacing: "0.18em", textTransform: "uppercase",
                  color: "#fff", fontWeight: 500,
                }}>Browse +</span>
              </label>
              <div style={{
                fontFamily: "var(--font-body)", fontSize: 11,
                color: "rgba(255,255,255,0.4)", marginTop: 6, lineHeight: 1.5,
              }}>
                Photos, PDFs, drawings, logs, video, ZIPs. Up to 10 files.
              </div>

              {/* Selected files list */}
              {files.length > 0 && (
                <ul style={{
                  listStyle: "none", padding: 0, margin: "16px 0 0",
                  border: "1px solid rgba(255,255,255,0.14)", background: "rgba(0,0,0,0.3)",
                }}>
                  {files.map((f, i) => (
                    <li key={i + f.name} style={{
                      display: "flex", alignItems: "center", justifyContent: "space-between",
                      gap: 12, padding: "10px 14px",
                      borderTop: i ? "1px solid rgba(255,255,255,0.14)" : "none",
                      fontFamily: "var(--font-body)", fontSize: 13,
                    }}>
                      <span style={{
                        color: "#fff", overflow: "hidden",
                        textOverflow: "ellipsis", whiteSpace: "nowrap",
                        flex: 1, minWidth: 0,
                      }}>{f.name}</span>
                      <span style={{ color: "rgba(255,255,255,0.55)", fontSize: 11, whiteSpace: "nowrap" }}>
                        {formatBytes(f.size)}
                      </span>
                      <button
                        type="button"
                        onClick={() => removeFile(i)}
                        style={{
                          background: "transparent", border: "none",
                          cursor: "pointer", padding: "4px 8px",
                          fontFamily: "var(--font-body)", fontSize: 11,
                          letterSpacing: "0.14em", textTransform: "uppercase",
                          color: "rgba(255,255,255,0.55)", fontWeight: 500,
                        }}
                        aria-label={`Remove ${f.name}`}
                      >Remove</button>
                    </li>
                  ))}
                </ul>
              )}
            </div>

            {/* Submit */}
            {submitError && (
              <p style={{
                fontFamily: "var(--font-body)", fontSize: 13.5,
                color: "#ff8a75", background: "rgba(255,90,60,0.1)",
                border: "1px solid rgba(255,90,60,0.35)",
                padding: "12px 14px", marginBottom: 16,
              }}>{submitError}</p>
            )}
            <button type="submit" disabled={submitting} style={{
              width: "100%",
              background: "#fff", color: "#000",
              border: "1px solid #fff",
              padding: "20px 22px", cursor: submitting ? "not-allowed" : "pointer",
              opacity: submitting ? 0.6 : 1,
              fontFamily: "var(--font-body)",
              fontSize: 13, fontWeight: 500,
              letterSpacing: "0.18em", textTransform: "uppercase",
              marginTop: 12,
            }}>{submitting ? "Sending…" : "Raise ticket →"}</button>
          </form>

          {/* ───── Reference panel ───── */}
          <aside style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            {/* What Solo support covers */}
            <div style={{
              background: "rgba(255,255,255,0.05)", border: "1px solid rgba(255,255,255,0.25)",
              padding: "30px 30px 34px",
            }}>
              <div style={{
                fontFamily: "var(--font-body)", fontSize: 10,
                letterSpacing: "0.22em", textTransform: "uppercase",
                color: "rgba(255,255,255,0.6)", marginBottom: 18, fontWeight: 500,
              }}>How Solo support works</div>
              <h3 style={{
                fontFamily: "var(--font-display)", fontWeight: 700,
                fontSize: 20, letterSpacing: "0.005em", textTransform: "uppercase",
                margin: "0 0 18px", color: "#fff",
              }}>Routed via the partner programme.</h3>
              <p style={{
                fontFamily: "var(--font-body)", fontSize: 14, lineHeight: 1.6,
                color: "rgba(255,255,255,0.78)", margin: 0,
              }}>
                Solo sells exclusively through approved partners — and your partner owns first-line support in your region. Tickets raised here are triaged by the Solo team and routed to the right partner contact.
              </p>
            </div>

            {/* Region phone numbers */}
            <div style={{
              background: "rgba(255,255,255,0.04)",
              border: "1px solid rgba(255,255,255,0.16)",
              padding: "26px 28px 28px",
            }}>
              <div style={{
                fontFamily: "var(--font-body)", fontSize: 10,
                letterSpacing: "0.22em", textTransform: "uppercase",
                color: "rgba(255,255,255,0.55)", marginBottom: 16, fontWeight: 500,
              }}>Regional support</div>
              <div style={{ display: "flex", flexDirection: "column" }}>
                {SUPPORT_REGIONS.map((r, i) => (
                  <div key={r.region} style={{
                    paddingTop: i ? 18 : 0,
                    paddingBottom: 18,
                    borderTop: i ? "1px solid rgba(255,255,255,0.14)" : "none",
                  }}>
                    <div style={{
                      display: "flex", justifyContent: "space-between",
                      alignItems: "baseline", marginBottom: 8,
                    }}>
                      <div style={{
                        fontFamily: "var(--font-display)", fontWeight: 700,
                        fontSize: 15, letterSpacing: "0.005em",
                        textTransform: "uppercase", color: "#fff",
                      }}>{r.region}</div>
                      <div style={{
                        fontFamily: "var(--font-body)", fontSize: 10,
                        letterSpacing: "0.18em", textTransform: "uppercase",
                        color: "rgba(255,255,255,0.55)", fontWeight: 500,
                      }}>{r.short}</div>
                    </div>
                    <a href={`tel:${r.phone.replace(/\s+/g, "")}`} style={{
                      display: "block",
                      fontFamily: "var(--font-body)", fontSize: 15,
                      color: "#fff", textDecoration: "none",
                      marginBottom: 6,
                    }}>{r.phone}</a>
                    <div style={{
                      fontFamily: "var(--font-body)", fontSize: 12,
                      color: "rgba(255,255,255,0.6)", lineHeight: 1.55,
                    }}>{r.note}</div>
                  </div>
                ))}
              </div>
              <div style={{
                marginTop: 4, paddingTop: 14, borderTop: "1px solid rgba(255,255,255,0.14)",
                fontFamily: "var(--font-body)", fontSize: 10,
                letterSpacing: "0.16em", textTransform: "uppercase",
                color: "rgba(255,255,255,0.4)",
              }}>
                // Replace placeholder numbers with real lines
              </div>
            </div>

            {/* Email fallback */}
            <div style={{
              background: "rgba(0,0,0,0.3)",
              border: "1px solid rgba(255,255,255,0.14)",
              padding: "22px 28px 24px",
            }}>
              <div style={{
                fontFamily: "var(--font-body)", fontSize: 10,
                letterSpacing: "0.22em", textTransform: "uppercase",
                color: "rgba(255,255,255,0.55)", marginBottom: 12, fontWeight: 500,
              }}>Email Solo direct</div>
              <a href={`mailto:${SUPPORT_INBOX}`} style={{
                fontFamily: "var(--font-display)", fontWeight: 700,
                fontSize: 16, letterSpacing: "0.005em",
                textTransform: "uppercase", color: "#fff",
                textDecoration: "underline",
                wordBreak: "break-all",
              }}>{SUPPORT_INBOX}</a>
              <div style={{
                fontFamily: "var(--font-body)", fontSize: 12,
                color: "rgba(255,255,255,0.6)", marginTop: 10, lineHeight: 1.5,
              }}>
                Use email if your issue is sensitive or you'd rather not use the form.
              </div>
            </div>
          </aside>
        </div>
      )}
    </ResellerShell>
  );
}

/* ──────────── My tickets tab ──────────── */
const MY_TICKET_STATUS_LABELS = { open: "Open", in_progress: "In Progress", resolved: "Resolved", closed: "Closed" };
const MY_TICKET_STATUS_COLORS = {
  open: "#e0a13f", in_progress: "#5b9fe0", resolved: "#4fc98a", closed: "rgba(255,255,255,0.5)",
};

function MyTicketsPanel() {
  const [state, setState] = useState({ status: "loading", tickets: [] });
  const [openId, setOpenId] = useState(null);

  const load = () => {
    fetch("/api/portal/tickets", { credentials: "same-origin" })
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then((data) => setState({ status: "ready", tickets: data.tickets || [] }))
      .catch(() => setState({ status: "error", tickets: [] }));
  };

  useEffect(load, []); // eslint-disable-line react-hooks/exhaustive-deps -- mount-only

  return (
    <div style={{ marginBottom: 40 }}>
      {state.status === "loading" && (
        <p style={{ fontFamily: "var(--font-body)", fontSize: 14, color: "rgba(255,255,255,0.6)" }}>Loading your tickets…</p>
      )}
      {state.status === "error" && (
        <p style={{ fontFamily: "var(--font-body)", fontSize: 14, color: "#ff8a75" }}>Couldn't load your tickets. Try refreshing the page.</p>
      )}
      {state.status === "ready" && state.tickets.length === 0 && (
        <p style={{ fontFamily: "var(--font-body)", fontSize: 14, color: "rgba(255,255,255,0.6)" }}>You haven't raised any support tickets yet.</p>
      )}
      {state.status === "ready" && state.tickets.length > 0 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          {state.tickets.map((t) => (
            <MyTicketRow
              key={t.id} ticket={t}
              open={openId === t.id}
              onToggle={() => setOpenId(openId === t.id ? null : t.id)}
              onSaved={load}
            />
          ))}
        </div>
      )}
    </div>
  );
}

function MyTicketRow({ ticket, open, onToggle, onSaved }) {
  return (
    <div data-testid={`my-ticket-row-${ticket.id}`} style={{ background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.16)" }}>
      <button
        type="button" onClick={onToggle} data-testid={`my-ticket-toggle-${ticket.id}`}
        style={{
          width: "100%", background: "none", border: "none", cursor: "pointer",
          padding: "18px 22px", display: "flex", justifyContent: "space-between",
          alignItems: "center", flexWrap: "wrap", gap: 12, textAlign: "left",
        }}>
        <div>
          <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 15, textTransform: "uppercase", color: "#fff" }}>
            {ticket.ticket_number}
          </div>
          <div style={{ fontFamily: "var(--font-body)", fontSize: 12.5, color: "rgba(255,255,255,0.65)", marginTop: 4 }}>
            <span style={{ color: MY_TICKET_STATUS_COLORS[ticket.status] || "rgba(255,255,255,0.65)", textTransform: "uppercase", letterSpacing: "0.08em", fontSize: 11 }}>
              {MY_TICKET_STATUS_LABELS[ticket.status] || ticket.status}
            </span>
            {" · "}{ticket.severity} · {ticket.ticket_type}
            {" · "}{ticket.message_count} repl{ticket.message_count === 1 ? "y" : "ies"}
            {ticket.asset_serial_number ? ` · ${ticket.asset_serial_number}` : ""}
          </div>
        </div>
        <span style={{ fontFamily: "var(--font-body)", fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase", color: "rgba(255,255,255,0.55)" }}>
          {open ? "Close ↑" : "View →"}
        </span>
      </button>
      {open && <MyTicketDetail ticketId={ticket.id} onSaved={onSaved} />}
    </div>
  );
}

function MyTicketDetail({ ticketId, onSaved }) {
  const [data, setData] = useState(null);
  const [error, setError] = useState("");
  const [busy, setBusy] = useState(false);
  const [reply, setReply] = useState("");

  const load = () => {
    fetch(`/api/portal/tickets/${ticketId}`, { credentials: "same-origin" })
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then((d) => setData(d))
      .catch(() => setError("Couldn't load this ticket."));
  };

  useEffect(load, [ticketId]); // eslint-disable-line react-hooks/exhaustive-deps

  if (!data) {
    return (
      <div style={{ borderTop: "1px solid rgba(255,255,255,0.14)", padding: "20px 22px" }}>
        {error ? <p style={{ color: "#ff8a75", fontFamily: "var(--font-body)", fontSize: 13 }}>{error}</p> : <p style={{ fontFamily: "var(--font-body)", fontSize: 13, color: "rgba(255,255,255,0.65)" }}>Loading…</p>}
      </div>
    );
  }

  const { ticket, messages } = data;
  const assetLabel = ticket.asset_serial_number
    ? `${ticket.asset_product_name} · ${ticket.asset_serial_number}`
    : null;

  const sendReply = async () => {
    if (!reply.trim()) return;
    setBusy(true);
    setError("");
    try {
      const res = await fetch(`/api/portal/tickets/${ticketId}/messages`, {
        method: "POST", credentials: "same-origin",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ body: reply.trim() }),
      });
      const d = await res.json().catch(() => ({}));
      if (!res.ok) { setError(d.error || "Something went wrong."); setBusy(false); return; }
      setReply("");
      load();
      onSaved();
    } catch {
      setError("Couldn't reach the server. Check your connection and try again.");
    } finally {
      setBusy(false);
    }
  };

  return (
    <div style={{ borderTop: "1px solid rgba(255,255,255,0.14)", padding: "20px 22px" }}>
      {error && <p style={{ color: "#ff8a75", fontFamily: "var(--font-body)", fontSize: 13, marginBottom: 12 }}>{error}</p>}

      {assetLabel && (
        <div style={{ marginBottom: 20 }}>
          <div style={{ fontFamily: "var(--font-body)", fontSize: 10, letterSpacing: "0.2em", textTransform: "uppercase", color: "rgba(255,255,255,0.55)", marginBottom: 8 }}>
            Asset / unit
          </div>
          <div style={{ fontFamily: "var(--font-body)", fontSize: 13.5, color: "#fff" }}>{assetLabel}</div>
        </div>
      )}

      <div style={{ marginBottom: 20 }}>
        <div style={{ fontFamily: "var(--font-body)", fontSize: 10, letterSpacing: "0.2em", textTransform: "uppercase", color: "rgba(255,255,255,0.55)", marginBottom: 8 }}>
          Description
        </div>
        <div style={{ fontFamily: "var(--font-body)", fontSize: 13.5, color: "#fff", lineHeight: 1.6, whiteSpace: "pre-wrap" }}>
          {ticket.description}
        </div>
      </div>

      <div style={{ height: 1, background: "rgba(255,255,255,0.14)", margin: "16px 0" }} />
      <div style={{ fontFamily: "var(--font-body)", fontSize: 10, letterSpacing: "0.2em", textTransform: "uppercase", color: "rgba(255,255,255,0.55)", marginBottom: 12 }}>
        Conversation ({messages.length})
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 20 }}>
        {messages.length === 0 && <p style={{ fontFamily: "var(--font-body)", fontSize: 13, color: "rgba(255,255,255,0.6)" }}>No replies yet — Solo support will respond within one working day.</p>}
        {messages.map((m) => (
          <div key={m.id} style={{
            padding: "12px 14px",
            background: m.author_type === "admin" ? "rgba(255,255,255,0.09)" : "rgba(255,255,255,0.04)",
            border: `1px solid ${m.author_type === "admin" ? "rgba(255,255,255,0.35)" : "rgba(255,255,255,0.16)"}`,
          }}>
            <div style={{ fontFamily: "var(--font-body)", fontSize: 10.5, letterSpacing: "0.1em", textTransform: "uppercase", color: "rgba(255,255,255,0.55)", marginBottom: 6 }}>
              {m.author_type === "admin" ? "Solo support" : "You"}
              {" · "}{m.created_at}
            </div>
            <div style={{ fontFamily: "var(--font-body)", fontSize: 13.5, color: "#fff", lineHeight: 1.55, whiteSpace: "pre-wrap" }}>{m.body}</div>
          </div>
        ))}
      </div>

      <label style={{ display: "block", marginBottom: 12 }}>
        <FieldLabel>Reply</FieldLabel>
        <textarea value={reply} onChange={(e) => setReply(e.target.value)} rows={3} style={{ ...inputStyle, resize: "vertical" }} />
      </label>
      <button
        type="button" onClick={sendReply} disabled={busy || !reply.trim()}
        data-testid={`my-ticket-reply-${ticketId}`}
        style={{
          background: "#fff", color: "#000", border: "1px solid #fff",
          padding: "12px 20px", cursor: busy || !reply.trim() ? "not-allowed" : "pointer",
          opacity: busy || !reply.trim() ? 0.6 : 1,
          fontFamily: "var(--font-body)", fontSize: 12, fontWeight: 500,
          letterSpacing: "0.14em", textTransform: "uppercase",
        }}>{busy ? "Sending…" : "Send reply"}</button>
    </div>
  );
}

/* ──────────── Shared field label / input style (dark theme) ──────────── */
function FieldLabel({ children }) {
  return (
    <div style={{
      fontFamily: "var(--font-body)", fontSize: 11,
      letterSpacing: "0.16em", color: "rgba(255,255,255,0.55)",
      textTransform: "uppercase", marginBottom: 8, fontWeight: 500,
    }}>{children}</div>
  );
}

// Simple outlined button matching ResellerShell's own "Sign out" button
// styling — used for the post-submit confirmation screen's actions.
function ShellButton({ onClick, children }) {
  return (
    <button
      type="button" onClick={onClick}
      style={{
        background: "none", border: "1px solid rgba(255,255,255,0.3)",
        color: "#fff", cursor: "pointer", padding: "14px 22px",
        fontFamily: "var(--font-body)", fontSize: 12, fontWeight: 500,
        letterSpacing: "0.14em", textTransform: "uppercase",
      }}
    >
      {children}
    </button>
  );
}

const inputStyle = {
  width: "100%", boxSizing: "border-box",
  background: "rgba(0,0,0,0.4)", border: "1px solid rgba(255,255,255,0.2)",
  color: "#fff", fontFamily: "var(--font-body)",
  fontSize: 15, padding: "12px 14px", outline: "none",
  transition: "border-color 140ms",
};

function formatBytes(bytes) {
  if (!bytes && bytes !== 0) return "";
  if (bytes < 1024) return bytes + " B";
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
  return (bytes / (1024 * 1024)).toFixed(1) + " MB";
}

Object.assign(window, { SupportPage });
