import { useState, useEffect } from 'react';
import { useClient } from 'hooks/useClient';
import { usePanelChannel } from 'hooks/usePanelChannel';
import { toast } from 'sonner';
import { Users, Search, FolderOpen, CircleCheck, CircleSlash, Clock, Loader2, Star, X } from 'lucide-react';
import { useSoulseekFavorites } from './useSoulseekFavorites';
import {
  SOULSEEK_USER_CHANNEL,
  type SlskdBrowseDirectory,
  type SlskdUserInfo,
  type SlskdUserStatus,
  type SoulseekUserRequest,
} from './shared';

// Users panel — look up a peer: their presence (online/away/offline), profile info (description, upload
// slots, queue), and optionally browse their shared folders. GET /users/{u}/status + /info fetch the
// header; GET /users/{u}/browse pulls the share tree (a flat directory list).
//
// This is also where the workspace's peer actions land: the username dropdown in search results and
// downloads publishes to 'soulseek:user', which we consume once (clearing it) to look the peer up and
// auto-browse. Favourites — Officer's own data, since slskd has no such concept — get their own section
// at the top, which also serves as this panel's landing content before any lookup.

type Loaded = {
  username: string;
  status: SlskdUserStatus | null;
  info: SlskdUserInfo | null;
};

const presenceStyle = (p?: string): { label: string; dot: string; icon: typeof CircleCheck } => {
  switch ((p ?? '').toLowerCase()) {
    case 'online':
      return { label: 'Online', dot: 'text-green-500', icon: CircleCheck };
    case 'away':
      return { label: 'Away', dot: 'text-amber-500', icon: Clock };
    default:
      return { label: 'Offline', dot: 'text-zinc-500', icon: CircleSlash };
  }
};

export const SoulseekUsers = () => {
  const client = useClient();
  const [query, setQuery] = useState('');
  const [loading, setLoading] = useState(false);
  const [peer, setPeer] = useState<Loaded | null>(null);
  const [dirs, setDirs] = useState<SlskdBrowseDirectory[] | null>(null);
  const [browsing, setBrowsing] = useState(false);
  const [request, setRequest] = usePanelChannel<SoulseekUserRequest | null>(SOULSEEK_USER_CHANNEL, null);
  const { favorites, isFavorite, toggle } = useSoulseekFavorites();

  const browse = async (username: string) => {
    setBrowsing(true);
    try {
      const tree = await client.get<SlskdBrowseDirectory[]>(
        `/slskd/api/v0/users/${encodeURIComponent(username)}/browse`,
      );
      setDirs([...tree].sort((a, b) => a.name.localeCompare(b.name)));
    } catch (err) {
      toast.error(`Browse failed: ${err instanceof Error ? err.message : String(err)}`);
    } finally {
      setBrowsing(false);
    }
  };

  const lookup = async (name: string, autoBrowse = false) => {
    const username = name.trim();
    if (!username || loading) return;
    setQuery(username);
    setLoading(true);
    setPeer(null);
    setDirs(null);
    const [status, info] = await Promise.allSettled([
      client.get<SlskdUserStatus>(`/slskd/api/v0/users/${encodeURIComponent(username)}/status`),
      client.get<SlskdUserInfo>(`/slskd/api/v0/users/${encodeURIComponent(username)}/info`),
    ]);
    setLoading(false);
    if (status.status === 'rejected' && info.status === 'rejected') {
      toast.error(`Couldn't reach ${username} — they may be offline.`);
      return;
    }
    setPeer({
      username,
      status: status.status === 'fulfilled' ? status.value : null,
      info: info.status === 'fulfilled' ? info.value : null,
    });
    if (autoBrowse) browse(username);
  };

  // Consume a peer request from the username dropdown. Cleared as it's handled, so switching away and
  // back doesn't re-run the (expensive) browse.
  useEffect(() => {
    if (!request) return;
    setRequest(null);
    lookup(request.username, request.browse);
    // lookup is recreated each render; the effect deliberately runs only when a request arrives.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [request]);

  const pres = presenceStyle(peer?.status?.presence);
  const PresIcon = pres.icon;

  return (
    <div className="flex h-full flex-col overflow-hidden">
      <div className="flex shrink-0 items-center gap-2 border-b p-3">
        <Users className="h-4 w-4 shrink-0 text-muted-foreground" />
        <form
          onSubmit={(ev) => {
            ev.preventDefault();
            lookup(query);
          }}
          className="flex flex-1 items-center gap-2"
        >
          <input
            value={query}
            onChange={(ev) => setQuery(ev.target.value)}
            placeholder="Look up a username…"
            className="h-9 min-w-0 flex-1 rounded-lg border bg-background px-3 text-sm outline-none focus:border-primary/50 focus:ring-2 focus:ring-primary/20"
          />
          <button
            type="submit"
            disabled={!query.trim() || loading}
            className="flex h-9 items-center gap-1.5 rounded-lg bg-primary px-3 text-sm text-primary-foreground transition hover:bg-primary/90 disabled:opacity-40"
          >
            {loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Search className="h-4 w-4" />}
            Look up
          </button>
        </form>
      </div>

      <div className="min-h-0 flex-1 overflow-y-auto p-4">
        <div className="mx-auto flex max-w-2xl flex-col gap-4">
          {/* Favorites — Officer's own data (slskd has no such concept). Always present, so the section
              doubles as the panel's landing content before any lookup. */}
          <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">
              <Star className="h-4 w-4 fill-amber-400 text-amber-400" />
              <span className="text-sm font-medium text-zinc-100">Favorites</span>
              {favorites.length > 0 && <span className="text-xs text-zinc-500">· {favorites.length}</span>}
            </div>
            {favorites.length === 0 ? (
              <p className="px-4 py-3 text-sm text-zinc-500">
                No favorites yet — add one from a peer's profile below, or from the username menu in search results and
                downloads.
              </p>
            ) : (
              <div className="max-h-64 divide-y divide-white/5 overflow-y-auto">
                {favorites.map((u) => {
                  const current = peer?.username === u;
                  return (
                    <div
                      key={u}
                      className={`flex items-center gap-2 px-4 py-2 text-sm transition-colors ${
                        current ? 'bg-primary/5' : 'hover:bg-white/[0.02]'
                      }`}
                    >
                      <button
                        type="button"
                        onClick={() => lookup(u)}
                        title={`Look up ${u}`}
                        className={`min-w-0 flex-1 truncate text-left transition ${
                          current ? 'font-medium text-primary' : 'text-zinc-200 hover:text-zinc-100'
                        }`}
                      >
                        {u}
                      </button>
                      <button
                        type="button"
                        onClick={() => toggle(u)}
                        title={`Remove ${u} from favorites`}
                        className="flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-zinc-500 transition hover:bg-white/10 hover:text-zinc-200"
                      >
                        <X className="h-3.5 w-3.5" />
                      </button>
                    </div>
                  );
                })}
              </div>
            )}
          </div>

          {!peer ? (
            <div className="flex flex-col items-center justify-center gap-2 py-10 text-center text-muted-foreground">
              <Users className="h-8 w-8" />
              <p className="text-sm">Enter a Soulseek username to see their profile and shares.</p>
            </div>
          ) : (
            <>
              {/* Profile */}
              <div className="rounded-xl border border-white/10 bg-zinc-950 p-4">
                <div className="flex items-center gap-3">
                  <div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-white/5 text-lg font-semibold text-zinc-300">
                    {peer.username.charAt(0).toUpperCase()}
                  </div>
                  <div className="min-w-0 flex-1">
                    <div className="truncate text-sm font-semibold text-zinc-100">{peer.username}</div>
                    <div className={`flex items-center gap-1.5 text-xs ${pres.dot}`}>
                      <PresIcon className="h-3.5 w-3.5" />
                      {pres.label}
                      {peer.status?.isPrivileged && <span className="text-amber-400">· privileged</span>}
                    </div>
                  </div>
                  <button
                    type="button"
                    onClick={() => toggle(peer.username)}
                    title={isFavorite(peer.username) ? 'Remove from favorites' : 'Add to favorites'}
                    className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-zinc-500 transition hover:bg-white/5 hover:text-zinc-200"
                  >
                    <Star className={`h-4 w-4 ${isFavorite(peer.username) ? 'fill-amber-400 text-amber-400' : ''}`} />
                  </button>
                </div>

                {peer.info && (
                  <>
                    <div className="mt-4 grid grid-cols-3 gap-2">
                      <Stat label="Upload slots" value={peer.info.uploadSlots ?? 0} />
                      <Stat label="Queue" value={peer.info.queueLength ?? 0} />
                      <Stat
                        label="Free slot"
                        value={peer.info.hasFreeUploadSlot ? 'Yes' : 'No'}
                        accent={peer.info.hasFreeUploadSlot ? 'text-green-400' : 'text-zinc-400'}
                      />
                    </div>
                    {peer.info.description && (
                      <p className="mt-3 whitespace-pre-wrap border-t border-white/5 pt-3 text-sm text-zinc-300">
                        {peer.info.description}
                      </p>
                    )}
                  </>
                )}
              </div>

              {/* Shares */}
              <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">
                  <FolderOpen className="h-4 w-4 text-zinc-400" />
                  <span className="text-sm font-medium text-zinc-100">Shared folders</span>
                  {dirs && <span className="text-xs text-zinc-500">· {dirs.length}</span>}
                  {!dirs && (
                    <button
                      type="button"
                      onClick={() => browse(peer.username)}
                      disabled={browsing}
                      className="ml-auto flex items-center gap-1.5 text-xs text-zinc-400 transition hover:text-zinc-100 disabled:opacity-40"
                    >
                      {browsing ? (
                        <Loader2 className="h-3.5 w-3.5 animate-spin" />
                      ) : (
                        <FolderOpen className="h-3.5 w-3.5" />
                      )}
                      {browsing ? 'Browsing…' : 'Browse shares'}
                    </button>
                  )}
                </div>
                {dirs &&
                  (dirs.length === 0 ? (
                    <p className="px-4 py-3 text-sm text-zinc-500">No shared folders.</p>
                  ) : (
                    <div className="max-h-96 divide-y divide-white/5 overflow-y-auto">
                      {dirs.map((d) => (
                        <div key={d.name} className="flex items-center gap-2 px-4 py-2 text-sm">
                          <FolderOpen className="h-3.5 w-3.5 shrink-0 text-zinc-500" />
                          <span className="min-w-0 flex-1 truncate text-zinc-200" title={d.name}>
                            {d.name}
                          </span>
                          <span className="shrink-0 text-xs tabular-nums text-zinc-500">
                            {d.fileCount} file{d.fileCount === 1 ? '' : 's'}
                          </span>
                        </div>
                      ))}
                    </div>
                  ))}
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
};

type StatProps = { label: string; value: string | number; accent?: string };

const Stat = ({ label, value, accent = 'text-zinc-100' }: StatProps) => (
  <div className="flex flex-col gap-1 rounded-lg border border-white/5 bg-white/[0.02] px-3 py-2">
    <span className="text-xs text-zinc-500">{label}</span>
    <span className={`text-lg font-semibold tabular-nums ${accent}`}>{value}</span>
  </div>
);
