import { useState, useEffect, useMemo } from 'react';
import { Link } from 'react-router';
import { useClient } from 'hooks/useClient';
import { ArrowDownToLine, ArrowUpFromLine, Search, RefreshCw, Radio } from 'lucide-react';
import {
  SEARCH_PARAM,
  formatWhen,
  soulseekSectionPath,
  transferPhase,
  type SlskdApplication,
  type SlskdSearchSummary,
  type SlskdTransferUser,
  type TransferPhase,
} from './shared';

// Dashboard — the at-a-glance overview for the /soulseek workspace: connection health, live
// download/upload tallies, and the most recent searches. Read-only aggregation over the same slskd
// endpoints the other panels use; every tile and row is a real link into the section it summarises, and
// a recent search links to that search rather than to the search screen's front page.

const POLL_MS = 2000;

type Tally = Record<TransferPhase, number>;
const emptyTally = (): Tally => ({ downloading: 0, queued: 0, done: 0, failed: 0 });
const tally = (users: SlskdTransferUser[]): Tally => {
  const t = emptyTally();
  for (const u of users) for (const d of u.directories ?? []) for (const f of d.files ?? []) t[transferPhase(f.state)]++;
  return t;
};

export const SoulseekDashboard = () => {
  const client = useClient();
  const [app, setApp] = useState<SlskdApplication | null>(null);
  const [downloads, setDownloads] = useState<Tally>(emptyTally);
  const [uploads, setUploads] = useState<Tally>(emptyTally);
  const [searches, setSearches] = useState<SlskdSearchSummary[]>([]);

  useEffect(() => {
    let cancelled = false;
    const tick = async () => {
      const [a, d, u, s] = await Promise.allSettled([
        client.get<SlskdApplication>('/slskd/api/v0/application'),
        client.get<SlskdTransferUser[]>('/slskd/api/v0/transfers/downloads'),
        client.get<SlskdTransferUser[]>('/slskd/api/v0/transfers/uploads'),
        client.get<SlskdSearchSummary[]>('/slskd/api/v0/searches'),
      ]);
      if (cancelled) return;
      if (a.status === 'fulfilled') setApp(a.value);
      if (d.status === 'fulfilled') setDownloads(tally(d.value));
      if (u.status === 'fulfilled') setUploads(tally(u.value));
      if (s.status === 'fulfilled')
        setSearches([...s.value].sort((x, y) => new Date(y.startedAt).getTime() - new Date(x.startedAt).getTime()));
    };
    tick();
    const timer = setInterval(tick, POLL_MS);
    return () => {
      cancelled = true;
      clearInterval(timer);
    };
    // useClient() is a fresh object each render — poll on a stable interval only.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const server = app?.server;
  const connected = server?.isConnected ?? false;
  const recent = useMemo(() => searches.slice(0, 6), [searches]);

  return (
    <div className="h-full overflow-y-auto p-4">
      <div className="mx-auto flex max-w-3xl flex-col gap-4">
        {/* Connection */}
        <div className="flex items-center gap-3 rounded-xl border border-white/10 bg-zinc-950 px-4 py-3">
          <Radio className="h-4 w-4 shrink-0 text-zinc-400" />
          <span className={`inline-block h-2.5 w-2.5 shrink-0 rounded-full ${connected ? 'bg-green-500' : 'bg-red-500'}`} />
          <div className="min-w-0 flex-1">
            <div className="truncate text-sm font-medium text-zinc-100">{server?.state ?? 'Unknown'}</div>
            {server?.address && <div className="truncate text-xs text-zinc-500">{server.address}</div>}
          </div>
          {app?.version?.current && (
            <span className="shrink-0 text-xs text-zinc-500">
              v{app.version.current}
              {app.version.isUpdateAvailable ? ' · update available' : ''}
            </span>
          )}
        </div>

        {/* Downloads */}
        <Section title="Downloads" icon={<ArrowDownToLine className="h-4 w-4" />} to={soulseekSectionPath('downloads')}>
          <Tile label="Downloading" value={downloads.downloading} dot="bg-blue-500" />
          <Tile label="Queued" value={downloads.queued} dot="bg-amber-500" />
          <Tile label="Completed" value={downloads.done} dot="bg-green-500" />
          <Tile label="Failed" value={downloads.failed} dot="bg-red-500" />
        </Section>

        {/* Uploads */}
        <Section title="Uploads" icon={<ArrowUpFromLine className="h-4 w-4" />} to={soulseekSectionPath('uploads')}>
          <Tile label="Uploading" value={uploads.downloading} dot="bg-blue-500" />
          <Tile label="Queued" value={uploads.queued} dot="bg-amber-500" />
          <Tile label="Completed" value={uploads.done} dot="bg-green-500" />
          <Tile label="Failed" value={uploads.failed} dot="bg-red-500" />
        </Section>

        {/* Recent searches */}
        <div className="rounded-xl border border-white/10 bg-zinc-950">
          <div className="flex items-center gap-2 border-b border-white/10 px-4 py-2.5">
            <Search className="h-4 w-4 text-zinc-400" />
            <span className="text-sm font-medium text-zinc-100">Recent searches</span>
            <Link
              to={soulseekSectionPath('search')}
              className="ml-auto text-xs text-zinc-500 transition hover:text-zinc-200"
            >
              View all
            </Link>
          </div>
          {recent.length === 0 ? (
            <p className="px-4 py-3 text-sm text-zinc-500">No searches yet.</p>
          ) : (
            <div className="divide-y divide-white/5">
              {recent.map((s) => (
                <Link
                  key={s.id}
                  to={`${soulseekSectionPath('search')}?${SEARCH_PARAM}=${s.id}`}
                  className="flex w-full items-center gap-3 px-4 py-2 text-left transition hover:bg-white/5"
                >
                  <span className="min-w-0 flex-1 truncate text-sm text-zinc-200">{s.searchText}</span>
                  <span className="shrink-0 text-xs tabular-nums text-zinc-500">{s.responseCount} responses</span>
                  <span className="shrink-0 text-xs text-zinc-600">{formatWhen(s.startedAt)}</span>
                </Link>
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

type SectionProps = { title: string; icon: React.ReactNode; to: string; children: React.ReactNode };

const Section = ({ title, icon, to, children }: SectionProps) => (
  <div className="rounded-xl border border-white/10 bg-zinc-950">
    <Link
      to={to}
      className="flex w-full items-center gap-2 border-b border-white/10 px-4 py-2.5 text-left transition hover:bg-white/5"
    >
      <span className="text-zinc-400">{icon}</span>
      <span className="text-sm font-medium text-zinc-100">{title}</span>
      <RefreshCw className="ml-auto h-3 w-3 text-zinc-600" />
    </Link>
    <div className="grid grid-cols-2 gap-2 p-3 sm:grid-cols-4">{children}</div>
  </div>
);

type TileProps = { label: string; value: number; dot: string };

const Tile = ({ label, value, dot }: TileProps) => (
  <div className="flex flex-col gap-1 rounded-lg border border-white/5 bg-white/[0.02] px-3 py-2.5">
    <div className="flex items-center gap-1.5 text-xs text-zinc-500">
      <span className={`h-2 w-2 rounded-full ${dot}`} />
      {label}
    </div>
    <div className="text-xl font-semibold tabular-nums text-zinc-100">{value}</div>
  </div>
);
