import { FormEvent, useEffect, useMemo, useState } from "react";
import { invoke } from "@tauri-apps/api/core";
import { AppHeader } from "./components/AppHeader";
import { ResourcePanel } from "./components/ResourcePanel";
import { StatusCard } from "./components/StatusCard";

type AccessProfile = {
  id: string;
  name: string;
  description: string;
  fullTunnel: boolean;
  destinations: string[];
};

type EnrollmentState = {
  assignedIp: string;
  resources: string[];
  availableProfiles: AccessProfile[];
  selectedProfileId: string | null;
  profileRevision: number;
  gatewayEndpoint: string;
  profilePath: string;
  lastSyncTime: string;
  tunnelStrategy: string;
};

function formatInvokeError(err: unknown, fallback: string) {
  if (typeof err === "string" && err.trim().length > 0) {
    return err;
  }

  if (err instanceof Error && err.message.trim().length > 0) {
    return err.message;
  }

  return fallback;
}

function isAlreadyRunningError(err: unknown) {
  const message = formatInvokeError(err, "");
  return message.toLowerCase().includes("already installed and running");
}

function currentProfileLabel(state: EnrollmentState | null) {
  if (!state) {
    return "Not provisioned";
  }

  const selectedProfile = state.availableProfiles.find((profile) => profile.id === state.selectedProfileId);
  if (selectedProfile) {
    return selectedProfile.name;
  }

  if (state.resources.includes("0.0.0.0/0")) {
    return "Full tunnel";
  }

  if (state.resources.length === 1) {
    return "Single resource access";
  }

  return `Split tunnel (${state.resources.length} resources)`;
}

export function App() {
  const [serverUrl, setServerUrl] = useState("http://localhost");
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [loading, setLoading] = useState(false);
  const [syncing, setSyncing] = useState(false);
  const [selectingProfile, setSelectingProfile] = useState(false);
  const [tunnelActionPending, setTunnelActionPending] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [connected, setConnected] = useState(false);
  const [state, setState] = useState<EnrollmentState | null>(null);
  async function refreshTunnelStatus() {
    try {
      const active = await invoke<boolean>("tunnel_status");
      setConnected(active);
    } catch {
      setConnected(false);
    }
  }

  useEffect(() => {
    void invoke<EnrollmentState | null>("load_state")
      .then(async (value) => {
        if (value) {
          setState(value);
          await refreshTunnelStatus();
        }
      })
      .catch(() => undefined);
  }, []);

  useEffect(() => {
    if (!state) {
      setConnected(false);
      return undefined;
    }

    void refreshTunnelStatus();
    const timer = window.setInterval(() => {
      void refreshTunnelStatus();
    }, 5000);

    return () => window.clearInterval(timer);
  }, [state]);

  const profileLabel = useMemo(() => currentProfileLabel(state), [state]);

  async function waitForTunnelStatus(expected: boolean) {
    for (let attempt = 0; attempt < 8; attempt += 1) {
      try {
        const active = await invoke<boolean>("tunnel_status");
        setConnected(active);
        if (active === expected) {
          return active;
        }
      } catch {
        if (!expected) {
          setConnected(false);
          return false;
        }
      }

      await new Promise((resolve) => window.setTimeout(resolve, 500));
    }

    return invoke<boolean>("tunnel_status")
      .then(async (active) => {
        setConnected(active);
        return active;
      })
      .catch(() => false);
  }

  async function onSubmit(event: FormEvent) {
    event.preventDefault();
    setLoading(true);
    setError(null);

    try {
      const result = await invoke<EnrollmentState>("enroll_device", {
        payload: { serverUrl, username, password }
      });
      setState(result);
    } catch (err) {
      setError(formatInvokeError(err, "Enrollment failed"));
    } finally {
      setLoading(false);
    }
  }

  async function onSyncProfile() {
    setSyncing(true);
    setError(null);

    try {
      const result = await invoke<EnrollmentState>("sync_profile");
      setState(result);
      await refreshTunnelStatus();
    } catch (err) {
      setError(formatInvokeError(err, "Profile sync failed"));
    } finally {
      setSyncing(false);
    }
  }

  async function onSelectProfile(profileId: string) {
    if (!state || profileId === state.selectedProfileId) {
      return;
    }

    setSelectingProfile(true);
    setError(null);

    try {
      const result = await invoke<EnrollmentState>("select_access_profile", { profileId });
      setState(result);
      await refreshTunnelStatus();
    } catch (err) {
      setError(formatInvokeError(err, "Profile selection failed"));
    } finally {
      setSelectingProfile(false);
    }
  }

  async function toggleConnection() {
    const command = connected ? "disconnect_tunnel" : "connect_tunnel";
    setTunnelActionPending(true);
    try {
      if (!connected) {
        const syncedState = await invoke<EnrollmentState>("connect_tunnel");
        setState(syncedState);
      } else {
        await invoke(command);
      }
      const active = await waitForTunnelStatus(!connected);
      setConnected(active);
      if (!connected && !active) {
        setError("Tunnel was installed, but no active interface could be verified yet.");
      } else if (connected && active) {
        setError("Tunnel could not be stopped cleanly yet.");
      } else {
        setError(null);
      }
    } catch (err) {
      if (!connected && isAlreadyRunningError(err)) {
        const active = await waitForTunnelStatus(true);
        setConnected(active);
        if (active) {
          setError(null);
          return;
        }
      }
      setError(formatInvokeError(err, "Tunnel action failed"));
    } finally {
      setTunnelActionPending(false);
    }
  }

  async function resetEnrollment() {
    try {
      await invoke("clear_session");
      setConnected(false);
      setState(null);
      setError(null);
    } catch (err) {
      setError(formatInvokeError(err, "Unable to clear local profile"));
    }
  }

  return (
    <div className="client-shell">
      <div className="app-shell">
        <AppHeader
          busy={tunnelActionPending}
          connected={connected}
          enrolled={Boolean(state)}
          onLogout={resetEnrollment}
          onSync={onSyncProfile}
          onToggleConnection={toggleConnection}
          syncing={syncing}
        />

        <div className="body-grid">
          {!state ? (
            <section className="login-card">
              <div className="panel-head">
                <div>
                  <p className="section-eyebrow">Sign in</p>
                  <h2>Provision device</h2>
                </div>
              </div>
              <form onSubmit={onSubmit}>
                <label>
                  VPN server address
                  <input value={serverUrl} onChange={(event) => setServerUrl(event.target.value)} />
                </label>
                <label>
                  Username
                  <input value={username} onChange={(event) => setUsername(event.target.value)} />
                </label>
                <label>
                  Password
                  <input type="password" value={password} onChange={(event) => setPassword(event.target.value)} />
                </label>
                {error ? <div className="error">{error}</div> : null}
                <div className="login-actions">
                  <button className="action-button action-button-primary" disabled={loading} type="submit">
                    {loading ? "Provisioning..." : "Sign in"}
                  </button>
                </div>
              </form>
            </section>
          ) : (
            <div className="main-column">
              <StatusCard
                accessLabel={profileLabel}
                assignedIp={state.assignedIp}
                connected={connected}
                gatewayEndpoint={state.gatewayEndpoint}
                lastSyncTime={state.lastSyncTime}
              />
              {error ? <div className="error">{error}</div> : null}
            </div>
          )}

          <ResourcePanel
            connected={connected}
            onReset={resetEnrollment}
            onSelectProfile={onSelectProfile}
            profileLabel={profileLabel}
            profiles={state?.availableProfiles ?? []}
            resources={state?.resources ?? []}
            selectedProfileId={state?.selectedProfileId ?? null}
            selectingProfile={selectingProfile || tunnelActionPending}
          />
        </div>
      </div>
    </div>
  );
}
