import { useEffect, useRef, useState } from 'react';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import styles from './UpdateChecker.module.css';

interface UpdateInfo {
  available: boolean;
  latest_version: string;
  current_version: string;
  release_notes: string;
  download_url: string;
  asset_name: string;
  asset_size: number;
}

interface ProgressEvent {
  downloaded: number;
  total: number;
}

type State =
  | { kind: 'idle' }
  | { kind: 'checking' }
  | { kind: 'up_to_date' }
  | { kind: 'error'; message: string }
  | { kind: 'available'; info: UpdateInfo }
  | { kind: 'downloading'; downloaded: number; total: number }
  | { kind: 'launching' };

function fmtBytes(n: number): string {
  if (n === 0) return '?';
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} KB`;
  return `${(n / (1024 * 1024)).toFixed(1)} MB`;
}

export default function UpdateChecker() {
  const [state, setState] = useState<State>({ kind: 'idle' });
  const [expanded, setExpanded] = useState(false);
  const unlisten = useRef<(() => void) | null>(null);

  useEffect(() => {
    return () => {
      unlisten.current?.();
    };
  }, []);

  async function handleCheck() {
    setState({ kind: 'checking' });
    setExpanded(false);
    try {
      const info = await invoke<UpdateInfo>('check_for_update');
      if (info.available) {
        setState({ kind: 'available', info });
        setExpanded(true);
      } else {
        setState({ kind: 'up_to_date' });
        // Auto-clear after 4 s
        setTimeout(() => setState({ kind: 'idle' }), 4000);
      }
    } catch (e) {
      setState({ kind: 'error', message: String(e) });
    }
  }

  async function handleInstall(info: UpdateInfo) {
    setState({ kind: 'downloading', downloaded: 0, total: info.asset_size });

    // Listen for streaming progress events from Rust
    unlisten.current?.();
    unlisten.current = await listen<ProgressEvent>('update-progress', (ev) => {
      setState({ kind: 'downloading', downloaded: ev.payload.downloaded, total: ev.payload.total });
    });

    try {
      await invoke('download_and_install_update', {
        downloadUrl: info.download_url,
        assetName: info.asset_name,
      });
      unlisten.current?.();
      setState({ kind: 'launching' });
    } catch (e) {
      unlisten.current?.();
      setState({ kind: 'error', message: String(e) });
    }
  }

  // ── Render ──────────────────────────────────────────────────────────────────

  if (state.kind === 'idle') {
    return (
      <button className={styles.checkBtn} onClick={handleCheck} title="Check for updates">
        [Update]
      </button>
    );
  }

  if (state.kind === 'checking') {
    return <span className={styles.status}>Checking…</span>;
  }

  if (state.kind === 'up_to_date') {
    return <span className={`${styles.status} ${styles.ok}`}>✓ Up to date</span>;
  }

  if (state.kind === 'error') {
    return (
      <span
        className={`${styles.status} ${styles.err}`}
        title={state.message}
        onClick={() => setState({ kind: 'idle' })}
      >
        ✗ Update error — click to dismiss
      </span>
    );
  }

  if (state.kind === 'launching') {
    return (
      <span className={`${styles.status} ${styles.ok}`}>
        ✓ Installer launched — complete the wizard to finish
      </span>
    );
  }

  if (state.kind === 'downloading') {
    const pct = state.total > 0 ? Math.round((state.downloaded / state.total) * 100) : 0;
    return (
      <div className={styles.downloadRow}>
        <span className={styles.downloadLabel}>
          Downloading… {fmtBytes(state.downloaded)}
          {state.total > 0 ? ` / ${fmtBytes(state.total)}` : ''}
        </span>
        <div className={styles.progressBar}>
          <div className={styles.progressFill} style={{ width: `${pct}%` }} />
        </div>
      </div>
    );
  }

  // state.kind === 'available'
  const { info } = state;
  return (
    <div className={styles.banner}>
      <div className={styles.bannerRow}>
        <span className={styles.bannerTitle}>
          ✦ v{info.latest_version} available
        </span>
        <button className={styles.installBtn} onClick={() => handleInstall(info)}>
          Install Update
        </button>
        <button
          className={styles.toggleBtn}
          onClick={() => setExpanded((e) => !e)}
          title={expanded ? 'Hide notes' : 'Show notes'}
        >
          {expanded ? '▴' : '▾'}
        </button>
        <button
          className={styles.dismissBtn}
          onClick={() => setState({ kind: 'idle' })}
          title="Dismiss"
        >
          ✕
        </button>
      </div>
      {expanded && info.release_notes && (
        <div className={styles.notes}>
          <pre className={styles.notesText}>{info.release_notes}</pre>
        </div>
      )}
    </div>
  );
}
