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

type EnrollmentState = {
  assignedIp: string;
  resources: string[];
  profileRevision: number;
  gatewayEndpoint: string;
  profilePath: string;
  lastSyncTime: string;
  tunnelStrategy: string;
};

type TunnelMetrics = {
  active: boolean;
  rxBytes: number;
  txBytes: number;
};

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";
  }

  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)`;
}

function formatDataSize(bytes: number) {
  if (!bytes) {
    return "0 B";
  }

  const units = ["B", "KB", "MB", "GB", "TB"];
  let value = bytes;
  let unitIndex = 0;

  while (value >= 1024 && unitIndex < units.length - 1) {
    value /= 1024;
    unitIndex += 1;
  }

  return `${value >= 100 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[unitIndex]}`;
}

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 [error, setError] = useState<string | null>(null);
  const [connected, setConnected] = useState(false);
  const [state, setState] = useState<EnrollmentState | null>(null);
  const [metrics, setMetrics] = useState<TunnelMetrics>({
    active: false,
    rxBytes: 0,
    txBytes: 0
  });

  async function refreshTunnelMetrics() {
    try {
      const value = await invoke<TunnelMetrics>("tunnel_metrics");
      setMetrics(value);
      setConnected(value.active);
    } catch {
      try {
        const active = await invoke<boolean>("tunnel_status");
        setConnected(active);
        setMetrics((current) => ({ ...current, active }));
      } catch {
        setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
        setConnected(false);
      }
    }
  }

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

  useEffect(() => {
    if (!state) {
      setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
      return undefined;
    }

    void refreshTunnelMetrics();
    const timer = window.setInterval(() => {
      void refreshTunnelMetrics();
    }, 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) {
          await refreshTunnelMetrics();
          return active;
        }
      } catch {
        if (!expected) {
          setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
          setConnected(false);
          return false;
        }
      }

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

    return invoke<boolean>("tunnel_status")
      .then(async (active) => {
        setConnected(active);
        await refreshTunnelMetrics();
        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);
      setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
    } 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 refreshTunnelMetrics();
    } catch (err) {
      setError(formatInvokeError(err, "Profile sync failed"));
    } finally {
      setSyncing(false);
    }
  }

  async function toggleConnection() {
    const command = connected ? "disconnect_tunnel" : "connect_tunnel";
    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"));
    }
  }

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

  return (
    <div className="client-shell">
      <div className="app-frame">
        <div className="top-strip">
          <div className="brand-lockup">
            <img src="/icon.png" alt="NexaVPN" />
            <div className="brand-copy">
              <p className="eyebrow">NexaVPN</p>
              <h1>VPN Client</h1>
              <p>{state ? "Private access client" : "Sign in to add this device"}</p>
            </div>
          </div>
          <div className="top-actions">
            {state ? (
              <button className="shell-button-secondary" disabled={syncing} onClick={onSyncProfile} type="button">
                {syncing ? "Syncing..." : "Sync"}
              </button>
            ) : null}
            {state ? (
              <button className="shell-button-secondary" onClick={resetEnrollment} type="button">
                Logout
              </button>
            ) : null}
            <button className="shell-button" disabled={!state} onClick={toggleConnection} type="button">
              {!state ? "Provision first" : connected ? "Disconnect" : "Connect"}
            </button>
          </div>
        </div>

        <div className="body-grid">
          {!state ? (
            <section className="login-panel">
              <div className="surface-header">
                <div>
                  <p className="eyebrow">Sign in</p>
                  <h3>Provision device</h3>
                </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-card-actions">
                  <button className="shell-button" disabled={loading} type="submit">
                    {loading ? "Provisioning..." : "Sign in"}
                  </button>
                </div>
              </form>
            </section>
          ) : (
            <section className="status-panel">
              <div className="status-top">
                <div>
                  <p className="eyebrow">Status</p>
                  <h3>{connected ? "Connected" : "Disconnected"}</h3>
                  <div className="status-state">
                    <span className={`status-dot ${connected ? "online" : ""}`} />
                    {connected ? "Tunnel active" : "Ready"}
                  </div>
                </div>
              </div>

              <div className="surface">
                <div className="surface-header">
                  <div>
                    <p className="eyebrow">Connection</p>
                    <h4>Overview</h4>
                  </div>
                </div>
                <div className="status-grid">
                  <div className="detail-card">
                    <span>Assigned VPN IP</span>
                    <strong>{state.assignedIp}</strong>
                  </div>
                  <div className="detail-card">
                    <span>Gateway endpoint</span>
                    <strong>{state.gatewayEndpoint}</strong>
                  </div>
                  <div className="detail-card">
                    <span>Access</span>
                    <strong>{profileLabel}</strong>
                  </div>
                  <div className="detail-card">
                    <span>Last sync</span>
                    <strong>{state.lastSyncTime}</strong>
                  </div>
                  <div className="detail-card">
                    <span>Received</span>
                    <strong>{formatDataSize(metrics.rxBytes)}</strong>
                  </div>
                  <div className="detail-card">
                    <span>Sent</span>
                    <strong>{formatDataSize(metrics.txBytes)}</strong>
                  </div>
                </div>
              </div>

              {error ? <div className="error">{error}</div> : null}
            </section>
          )}

          <aside className="status-panel">
            <div className="surface-header">
              <div>
                <p className="eyebrow">Access</p>
                <h4>Resources</h4>
              </div>
            </div>
            <p>Press <strong>Sync</strong> after policy changes.</p>
            <ul className="resource-stack">
              {(state?.resources ?? ["No resources assigned yet"]).map((resource) => (
                <li key={resource}>{resource}</li>
              ))}
            </ul>
            {state ? (
              <button className="shell-button-secondary" onClick={resetEnrollment} type="button">
                Neu einbinden
              </button>
            ) : null}
          </aside>
        </div>
      </div>
    </div>
  );
}
