import { useEffect, useState } from "react";
import { api } from "../api/client";
import { showError, showSuccess } from "../banner";
import type { AuthResponse } from "../types/api";
import { GarminMFAModal } from "./GarminMFAModal";
import { SyncModal } from "./SyncModal";

export function GarminConnection({ onBeforeConnect }: { onBeforeConnect?: () => Promise<void> }) {
  const [auth, setAuth] = useState<AuthResponse | null>(null);
  const [busy, setBusy] = useState(false);
  // There's no real Garmin logout -- the backend session just sits idle.
  // "Disconnect" only hides that and shows Connect again locally; a real
  // login (connect()) clears it.
  const [disconnected, setDisconnected] = useState(false);
  const [showSyncModal, setShowSyncModal] = useState(false);

  // Auth status alone -- sync status is polled by SyncModal itself while
  // it's open, so this no longer needs the "poll faster while syncing"
  // dynamic interval it used to have.
  useEffect(() => {
    api.authStatus().then(setAuth).catch((e) => showError(String(e)));
    const interval = setInterval(() => {
      api.authStatus().then(setAuth).catch(() => {});
    }, 6000);
    return () => clearInterval(interval);
  }, []);

  async function connect() {
    setBusy(true);
    try {
      await onBeforeConnect?.();
      const result = await api.login();
      setAuth(result);
      setDisconnected(false);
      if (result.status === "authenticated") showSuccess("Connected to Garmin successfully.");
    } catch (e) {
      showError(String(e));
    } finally {
      setBusy(false);
    }
  }

  function disconnect() {
    setDisconnected(true);
  }

  async function submitMFA(code: string) {
    if (!code.trim()) return;
    setBusy(true);
    try {
      const result = await api.submitMFA(code.trim());
      setAuth(result);
      if (result.status === "authenticated") showSuccess("Connected to Garmin successfully.");
    } catch (e) {
      showError(String(e));
    } finally {
      setBusy(false);
    }
  }

  async function sync() {
    setBusy(true);
    try {
      await api.syncRun();
      setShowSyncModal(true);
    } catch (e) {
      showError(String(e));
    } finally {
      setBusy(false);
    }
  }

  async function resetAll() {
    if (!window.confirm("This deletes every synced activity, lap, and kind assignment, then starts a fresh pull from Garmin next sync. This cannot be undone. Continue?")) {
      return;
    }
    setBusy(true);
    try {
      await api.resetSync();
      // Reset runs as a background sync job; wait for it to actually finish
      // before reloading, otherwise other pages (e.g. Activities) would
      // still show the just-deleted activities from their own stale state.
      let status = await api.syncStatus();
      while (status.in_progress) {
        await new Promise((resolve) => setTimeout(resolve, 300));
        status = await api.syncStatus();
      }
      window.location.reload();
    } catch (e) {
      showError(String(e));
      setBusy(false);
    }
  }

  const status = disconnected ? "unknown" : auth?.status ?? "unknown";

  return (
    <div className="garmin-connection">
      <div className="garmin-connection-row garmin-connection-main">
        <div className="garmin-connection-actions">
          {status !== "authenticated" && status !== "mfa_required" && (
            <button disabled={busy} onClick={connect}>
              Connect
            </button>
          )}

          {status === "authenticated" && (
            <>
              <button disabled={busy} onClick={sync}>
                Sync now
              </button>
              <button disabled={busy} onClick={disconnect}>
                Disconnect
              </button>
            </>
          )}

          {/* Reset all only wipes local DB state (see handleSyncReset) -- it
              doesn't touch the Garmin session, so it stays available even
              while disconnected/not-yet-connected. */}
          <button className="button-danger" disabled={busy} onClick={resetAll}>
            Reset all
          </button>
        </div>

        <div className="garmin-connection-status">
          <span className={`status-dot status-${status}`} />
          {/* Connected/not-connected is already conveyed by the
              Connect/Disconnect button itself -- only MFA/failed need a
              label, since no button distinguishes those from "not connected". */}
          {(status === "mfa_required" || status === "failed") && (
            <span className="status-label">
              {status === "mfa_required" ? "MFA code required" : "Connection failed"}
            </span>
          )}
        </div>
      </div>

      {status === "mfa_required" && (
        <GarminMFAModal message={auth?.message} busy={busy} onSubmit={submitMFA} onCancel={disconnect} />
      )}

      {!disconnected && auth?.message && status !== "authenticated" && (
        <p className="garmin-connection-message">{auth.message}</p>
      )}

      {showSyncModal && <SyncModal onClose={() => setShowSyncModal(false)} />}
    </div>
  );
}
