/* Dialer — Phase 1.
 *
 * Power dialer module for working a GHL CRM lead pile from a phone.
 * Calls go via tel: links (SIM dials), SMS goes via the GHL API.
 *
 * Sub-routes:
 *   /dialer            → /dialer/queue (default redirect)
 *   /dialer/queue      → lead list (the dial queue)
 *   /dialer/lead/{id}  → lead detail + call action
 *   /dialer/callbacks  → scheduled callbacks
 *   /dialer/stats      → session stats
 *   /dialer/settings   → GHL connection + templates
 *
 * Auth gate: every sub-route requires a Firebase Auth user. The rest of
 * Coaches' Brain stays on the localStorage coach.js pattern unchanged.
 * On first sign-in, the user maps their Firebase identity to a coach
 * name in Settings → "I am Simon".
 */
(function () {
  const { useState, useEffect, useMemo } = React;
  const {
    Button,
    Card,
    Pill,
    Icons,
    EmptyState,
    LoadingSpinner,
    SegmentedControl,
    Input,
    showToast,
    auth,
    dialer,
    coach,
  } = window.CC;

  // ────────────────────────────────────────────────────────────
  // Hooks
  // ────────────────────────────────────────────────────────────
  function useAuth() {
    const [state, setState] = useState({ user: null, ready: false });
    useEffect(() => auth.subscribe(setState), []);
    return state;
  }
  function useDialer() {
    const [state, setState] = useState({
      coach: null,
      settings: null,
      connected: false,
      userDoc: null,
    });
    useEffect(() => dialer.subscribe(setState), []);
    return state;
  }

  // ────────────────────────────────────────────────────────────
  // Tab root
  // ────────────────────────────────────────────────────────────
  function Dialer({ route }) {
    const a = useAuth();
    const d = useDialer();

    if (!a.ready) {
      return (
        <div className="cc-dialer cc-dialer--loading">
          <LoadingSpinner size="lg" delay={0} />
        </div>
      );
    }
    if (!a.user) {
      return <SignInGate />;
    }
    // Authed but no coach mapping yet → redirect to settings.
    if (!d.coach && !route.startsWith("/dialer/settings")) {
      return <CoachMappingPrompt user={a.user} />;
    }

    return (
      <div className="cc-dialer">
        <DialerNav route={route} />
        <DialerView route={route} d={d} a={a} />
      </div>
    );
  }

  function DialerNav({ route }) {
    const tabs = [
      { id: "queue", label: "Queue", path: "/dialer/queue" },
      { id: "callbacks", label: "Callbacks", path: "/dialer/callbacks" },
      { id: "stats", label: "Stats", path: "/dialer/stats" },
      { id: "settings", label: "Settings", path: "/dialer/settings" },
    ];
    return (
      <nav className="cc-dialer__nav">
        {tabs.map((t) => (
          <a
            key={t.id}
            href={`#${t.path}`}
            className={`cc-dialer__nav-link ${
              route.startsWith(t.path) ? "is-active" : ""
            }`}
          >
            {t.label}
          </a>
        ))}
      </nav>
    );
  }

  function DialerView({ route, d, a }) {
    if (route.startsWith("/dialer/lead/")) {
      const id = route.split("/dialer/lead/")[1];
      return <LeadPlaceholder id={id} />;
    }
    if (route.startsWith("/dialer/callbacks")) return <CallbacksPlaceholder />;
    if (route.startsWith("/dialer/stats")) return <StatsPlaceholder />;
    if (route.startsWith("/dialer/settings")) return <Settings d={d} a={a} />;
    return <Queue d={d} />;
  }

  // ────────────────────────────────────────────────────────────
  // Sign-in gate
  // ────────────────────────────────────────────────────────────
  function SignInGate() {
    const [signing, setSigning] = useState(false);
    async function go() {
      setSigning(true);
      try {
        await auth.signInGoogle();
      } catch (e) {
        showToast(e.message || "Sign-in failed.");
      } finally {
        setSigning(false);
      }
    }
    return (
      <div className="cc-dialer__gate">
        <div className="cc-dialer__gate-card">
          <h1>Dialer</h1>
          <p>
            This module handles real lead data and customer SMS. Sign in
            with Google to continue.
          </p>
          <Button size="lg" onClick={go} loading={signing}>
            Continue with Google
          </Button>
        </div>
      </div>
    );
  }

  function CoachMappingPrompt({ user }) {
    const [picking, setPicking] = useState(null);
    const choices = ["simon", "perrie"];
    async function pick(name) {
      setPicking(name);
      try {
        await dialer.setCoachMapping(name);
        showToast(`Linked as ${coach.label(name)}.`);
      } catch (e) {
        showToast("Couldn't save mapping.");
        setPicking(null);
      }
    }
    return (
      <div className="cc-dialer__gate">
        <div className="cc-dialer__gate-card">
          <h1>Welcome, {user.displayName || user.email}</h1>
          <p>Which coach are you?</p>
          <div className="cc-dialer__choice-row">
            {choices.map((c) => (
              <Button
                key={c}
                variant={picking === c ? "primary" : "secondary"}
                onClick={() => pick(c)}
                loading={picking === c}
              >
                I am {coach.label(c)}
              </Button>
            ))}
          </div>
        </div>
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Queue
  // ────────────────────────────────────────────────────────────
  function useOpportunities() {
    const [state, setState] = useState({
      ops: null,
      fetchedAt: 0,
      loading: false,
      error: null,
      pipeline: null,
    });
    useEffect(() => dialer.subscribeOpportunities(setState), []);
    return state;
  }

  // Tags that come from existing automations — surface non-system tags
  // first so the rail shows useful context.
  const SYSTEM_TAGS = new Set([
    "paidtrafficoptin",
    "watch_shift",
    "new_lead_alert",
    "valid whatsapp",
    "wa whatsapp 1.0 delivered",
    "ai off",
    "scheduled",
    "al_snooze",
    "ws_snooze",
    "pd_snooze",
    "needs appt bot",
    "5 min pickup yes",
    "cancelled",
    "ai booking error",
    "day1pm",
    "day2pm",
    "day3pm",
    "day4pm",
    "no show",
    "8 | utility [h] dnd",
  ]);
  function pickTags(tags, max = 3) {
    if (!Array.isArray(tags)) return [];
    const nonSystem = tags.filter((t) => !SYSTEM_TAGS.has((t || "").toLowerCase().trim()));
    return nonSystem.slice(0, max);
  }
  function shortPhone(phone) {
    if (!phone) return "";
    return "··· " + String(phone).slice(-5);
  }
  function daysSince(iso) {
    if (!iso) return null;
    const then = new Date(iso).getTime();
    if (!Number.isFinite(then)) return null;
    const days = Math.floor((Date.now() - then) / (24 * 60 * 60 * 1000));
    return days;
  }
  function formatDays(n) {
    if (n == null) return "";
    if (n === 0) return "today";
    if (n === 1) return "1d ago";
    return `${n}d ago`;
  }

  function Queue({ d }) {
    const op = useOpportunities();
    const [sortKey, setSortKey] = useState("oldest");
    const [stageFilter, setStageFilter] = useState(null); // null = use settings default

    useEffect(() => {
      if (d.connected && !op.ops && !op.loading) {
        dialer.fetchOpportunities().catch(() => {});
      }
    }, [d.connected]);

    if (!d.connected) {
      return (
        <div className="cc-dialer__pane">
          <header className="cc-dialer__head">
            <h1>Queue</h1>
            <Pill tone="due">GHL not connected</Pill>
          </header>
          <Card padding={20}>
            <EmptyState
              icon={Icons.phone(40)}
              title="Connect GHL first"
              subtitle="Settings → GHL connection."
              action={{
                label: "Open settings",
                onClick: () => (window.location.hash = "/dialer/settings"),
              }}
            />
          </Card>
        </div>
      );
    }

    const stages = (op.pipeline?.stages || []).slice().sort(
      (a, b) => (a.position || 0) - (b.position || 0)
    );
    const settingsStages =
      (d.settings && d.settings.queue_stages) || ["🚻 New Leads"];
    const activeStages = stageFilter == null ? settingsStages : [stageFilter];
    const stageNameSet = new Set(activeStages);
    const filtered = (op.ops || []).filter((o) =>
      stageNameSet.has(o.stageName)
    );

    const sorted = filtered.slice().sort((a, b) => {
      if (sortKey === "newest")
        return (
          new Date(b.createdAt || 0).getTime() -
          new Date(a.createdAt || 0).getTime()
        );
      if (sortKey === "stale")
        return (
          new Date(a.updatedAt || 0).getTime() -
          new Date(b.updatedAt || 0).getTime()
        );
      // oldest (default)
      return (
        new Date(a.createdAt || 0).getTime() -
        new Date(b.createdAt || 0).getTime()
      );
    });

    return (
      <div className="cc-dialer__pane">
        <header className="cc-dialer__head">
          <h1>Queue</h1>
          <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
            <Pill tone="onTrack">{filtered.length} leads</Pill>
            <Button
              size="sm"
              variant="ghost"
              onClick={() => dialer.fetchOpportunities({ force: true })}
              loading={op.loading}
            >
              Refresh
            </Button>
          </div>
        </header>

        <div className="cc-dialer__queue-controls">
          <div className="cc-dialer__queue-stages">
            <button
              type="button"
              className={`cc-dialer__chip ${
                stageFilter == null ? "is-active" : ""
              }`}
              onClick={() => setStageFilter(null)}
            >
              Default ({settingsStages.length})
            </button>
            {stages.map((s) => (
              <button
                key={s.id}
                type="button"
                className={`cc-dialer__chip ${
                  stageFilter === s.name ? "is-active" : ""
                }`}
                onClick={() => setStageFilter(s.name)}
              >
                {s.name}
              </button>
            ))}
          </div>
          <select
            className="cc-dialer__sort"
            value={sortKey}
            onChange={(e) => setSortKey(e.target.value)}
          >
            <option value="oldest">Oldest first</option>
            <option value="newest">Newest first</option>
            <option value="stale">Most stale (last update)</option>
          </select>
        </div>

        {op.error && (
          <Card padding={16}>
            <p style={{ margin: 0, color: "var(--danger)" }}>
              {op.error}
            </p>
            <p
              style={{
                margin: "4px 0 0",
                fontSize: 12,
                color: "var(--text-dim)",
              }}
            >
              Settings → GHL connection → Test if this persists.
            </p>
          </Card>
        )}

        {op.loading && !op.ops && (
          <div style={{ padding: 40, display: "flex", justifyContent: "center" }}>
            <LoadingSpinner size="md" delay={0} />
          </div>
        )}

        {op.ops && sorted.length === 0 && !op.loading && (
          <Card padding={20}>
            <EmptyState
              icon={Icons.phone(40)}
              title="No leads in this stage right now"
              subtitle={
                stageFilter
                  ? `Stage: ${stageFilter}`
                  : "Try a different stage filter."
              }
            />
          </Card>
        )}

        {sorted.length > 0 && (
          <ul className="cc-dialer__queue-list">
            {sorted.map((o) => (
              <li key={o.id}>
                <a
                  className="cc-dialer__queue-row"
                  href={`#/dialer/lead/${o.id}`}
                >
                  <div className="cc-dialer__queue-main">
                    <div className="cc-dialer__queue-name">
                      {o.contactName || o.name || "Unnamed"}
                    </div>
                    <div className="cc-dialer__queue-meta">
                      <span>{shortPhone(o.phone)}</span>
                      {o.source && <span>· {o.source}</span>}
                      <span>· {formatDays(daysSince(o.createdAt))}</span>
                    </div>
                  </div>
                  <div className="cc-dialer__queue-tags">
                    {pickTags(o.tags).map((t) => (
                      <span key={t} className="cc-dialer__tag">{t}</span>
                    ))}
                  </div>
                </a>
              </li>
            ))}
          </ul>
        )}

        {op.fetchedAt > 0 && (
          <p className="cc-dialer__fetched">
            Updated {Math.round((Date.now() - op.fetchedAt) / 1000)}s ago
          </p>
        )}
      </div>
    );
  }

  function LeadPlaceholder({ id }) {
    return (
      <div className="cc-dialer__pane">
        <header className="cc-dialer__head">
          <h1>Lead</h1>
        </header>
        <Card padding={20}>
          <EmptyState
            icon={Icons.phone(40)}
            title="Lead detail lands in checkpoint 3"
            subtitle={`opportunity_id: ${id}`}
          />
        </Card>
      </div>
    );
  }

  function CallbacksPlaceholder() {
    return (
      <div className="cc-dialer__pane">
        <header className="cc-dialer__head">
          <h1>Callbacks</h1>
        </header>
        <Card padding={20}>
          <EmptyState
            icon={Icons.calendar(40)}
            title="Callbacks land in checkpoint 4"
          />
        </Card>
      </div>
    );
  }

  function StatsPlaceholder() {
    return (
      <div className="cc-dialer__pane">
        <header className="cc-dialer__head">
          <h1>Stats</h1>
        </header>
        <Card padding={20}>
          <EmptyState icon={Icons.book(40)} title="Stats land in checkpoint 6" />
        </Card>
      </div>
    );
  }

  // ────────────────────────────────────────────────────────────
  // Settings (skeleton — GHL OAuth + identity. Full templates land later)
  // ────────────────────────────────────────────────────────────
  function Settings({ d, a }) {
    return (
      <div className="cc-dialer__pane">
        <header className="cc-dialer__head">
          <h1>Settings</h1>
        </header>

        <section className="cc-settings__section">
          <h2 className="cc-section-h2">Identity</h2>
          <Card padding={16}>
            <IdentityRow user={a.user} d={d} />
          </Card>
        </section>

        <section className="cc-settings__section">
          <h2 className="cc-section-h2">GHL connection</h2>
          <Card padding={16}>
            <GhlConnection d={d} />
          </Card>
        </section>

        <section className="cc-settings__section">
          <h2 className="cc-section-h2">Templates &amp; queue</h2>
          <Card padding={16}>
            <TemplatesPlaceholder />
          </Card>
        </section>
      </div>
    );
  }

  function IdentityRow({ user, d }) {
    async function out() {
      if (!confirm("Sign out of the dialer?")) return;
      try { await auth.signOut(); } catch {}
    }
    return (
      <div className="cc-dialer__identity">
        <div>
          <div className="cc-dialer__identity-line">
            Signed in as <strong>{user.displayName || user.email}</strong>
          </div>
          <div className="cc-dialer__identity-sub">
            Mapped to coach: <strong>{d.coach || "(not mapped)"}</strong>
          </div>
        </div>
        <Button variant="ghost" onClick={out}>Sign out</Button>
      </div>
    );
  }

  // Firebase Functions v2 runs on Cloud Run; the canonical URL is the
  // *.run.app subdomain. (Project-specific hash baked in.)
  const DEFAULT_REDIRECT_URI =
    "https://ghl-oauth-exchange-vzkzlybflq-ew.a.run.app";

  const SCOPE_PRESETS = [
    { value: "contacts.readonly", label: "contacts.readonly", required: true },
    { value: "opportunities.readonly", label: "opportunities.readonly", required: true },
    { value: "conversations.readonly", label: "conversations.readonly", required: true },
    { value: "conversations/message.write", label: "conversations/message.write", required: true },
    { value: "locations.readonly", label: "locations.readonly", required: true },
    { value: "calendars.readonly", label: "calendars.readonly (Phase 2)" },
    { value: "calendars.write", label: "calendars.write (Phase 2)" },
    { value: "opportunities.write", label: "opportunities.write (Phase 2)" },
  ];

  function GhlConnection({ d }) {
    const [clientId, setClientId] = useState("");
    const [clientSecret, setClientSecret] = useState("");
    const [redirectUri, setRedirectUri] = useState(DEFAULT_REDIRECT_URI);
    const [scopes, setScopes] = useState(SCOPE_PRESETS.filter((s) => s.required).map((s) => s.value));
    const [savingCreds, setSavingCreds] = useState(false);
    const [credsSaved, setCredsSaved] = useState(false);
    const [connecting, setConnecting] = useState(false);
    const [refreshing, setRefreshing] = useState(false);
    const [healthInfo, setHealthInfo] = useState(null);

    // Detect post-redirect status param.
    useEffect(() => {
      const params = new URLSearchParams(window.location.hash.split("?")[1] || "");
      if (params.get("status") === "connected") {
        showToast("GHL connected.");
        // Strip the status from the URL.
        window.location.hash = "/dialer/settings";
      }
    }, []);

    function toggleScope(s) {
      setScopes((prev) =>
        prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]
      );
    }

    async function saveCreds() {
      if (!clientId.trim() || !clientSecret.trim()) {
        showToast("Client ID and secret required.");
        return;
      }
      setSavingCreds(true);
      try {
        const res = await dialer.saveCredentials({
          clientId: clientId.trim(),
          clientSecret: clientSecret.trim(),
          redirectUri: redirectUri.trim() || DEFAULT_REDIRECT_URI,
          scopes,
        });
        if (res?.ok) {
          setCredsSaved(true);
          showToast("Credentials saved.");
          // Clear the secret from memory once saved.
          setClientSecret("");
        }
      } catch (e) {
        showToast(e.message || "Couldn't save credentials.");
      } finally {
        setSavingCreds(false);
      }
    }

    async function connect() {
      setConnecting(true);
      try {
        const returnUrl =
          window.location.origin + "/#/dialer/settings";
        const { url } = await dialer.startOAuth(returnUrl);
        window.location.href = url;
      } catch (e) {
        showToast(e.message || "Couldn't start OAuth.");
        setConnecting(false);
      }
    }

    async function testConnection() {
      setRefreshing(true);
      try {
        const res = await dialer.refreshConnection();
        setHealthInfo(res);
        showToast("Connection healthy.");
      } catch (e) {
        showToast(e.message || "Connection check failed.");
        setHealthInfo({ error: e.message });
      } finally {
        setRefreshing(false);
      }
    }

    async function disconnect() {
      if (!confirm("Disconnect from GHL? Your saved credentials stay; tokens are cleared.")) return;
      try {
        await dialer.disconnect();
        showToast("Disconnected.");
        setHealthInfo(null);
      } catch (e) {
        showToast(e.message || "Couldn't disconnect.");
      }
    }

    return (
      <div style={{ display: "grid", gap: 16 }}>
        <div className="cc-dialer__connection-status">
          {d.connected ? (
            <span className="cc-dialer__status-badge cc-dialer__status-badge--ok">
              {Icons.check(14)} Connected
            </span>
          ) : (
            <span className="cc-dialer__status-badge">Not connected</span>
          )}
          {d.connected && (
            <div className="cc-dialer__status-actions">
              <Button size="sm" variant="ghost" onClick={testConnection} loading={refreshing}>
                Test
              </Button>
              <Button size="sm" variant="ghost" onClick={disconnect}>
                Disconnect
              </Button>
            </div>
          )}
        </div>

        {healthInfo?.scopes && (
          <div className="cc-dialer__scopes">
            <div className="cc-dialer__scopes-head">Granted scopes</div>
            <div className="cc-dialer__scopes-list">
              {healthInfo.scopes.map((s) => (
                <span key={s} className="cc-dialer__scope-pill">{s}</span>
              ))}
            </div>
          </div>
        )}

        <details className="cc-dialer__details" open={!d.connected}>
          <summary>OAuth credentials</summary>
          <div style={{ display: "grid", gap: 12, marginTop: 12 }}>
            <Input
              label="Client ID"
              value={clientId}
              onChange={setClientId}
              placeholder="From your GHL marketplace app"
            />
            <Input
              label="Client secret"
              value={clientSecret}
              onChange={setClientSecret}
              type="password"
              placeholder={credsSaved ? "(saved — re-enter to update)" : "From your GHL marketplace app"}
            />
            <Input
              label="Redirect URI"
              value={redirectUri}
              onChange={setRedirectUri}
              placeholder={DEFAULT_REDIRECT_URI}
            />
            <div className="cc-dialer__scopes">
              <div className="cc-dialer__scopes-head">Scopes</div>
              <div className="cc-dialer__scopes-list">
                {SCOPE_PRESETS.map((s) => (
                  <label
                    key={s.value}
                    className={`cc-dialer__scope-toggle ${
                      scopes.includes(s.value) ? "is-on" : ""
                    } ${s.required ? "is-required" : ""}`}
                  >
                    <input
                      type="checkbox"
                      checked={scopes.includes(s.value)}
                      onChange={() => toggleScope(s.value)}
                    />
                    <span>{s.label}</span>
                  </label>
                ))}
              </div>
            </div>
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
              <Button onClick={saveCreds} loading={savingCreds}>
                {credsSaved ? "Update credentials" : "Save credentials"}
              </Button>
            </div>
          </div>
        </details>

        {!d.connected && (
          <div className="cc-dialer__connect-row">
            <p className="cc-dialer__hint">
              After saving credentials, click Connect to authorise this
              app in GHL. You'll be redirected away and back.
            </p>
            <Button size="lg" onClick={connect} loading={connecting}>
              Connect GHL
            </Button>
          </div>
        )}
      </div>
    );
  }

  function TemplatesPlaceholder() {
    return (
      <p className="cc-dialer__hint">
        Pre-text templates, queue stage filters, send delay — all land
        in checkpoint 5.
      </p>
    );
  }

  window.CC = window.CC || {};
  window.CC.Dialer = Dialer;
})();
