import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import {
  fetchChannels, fetchSounds, playSound, setVolumeLive, getVolume,
  adminStatus, adminLogin, adminLogout, adminDelete, adminRename,
  playUrl, fetchCategories, createCategory, assignCategories, clearBadges,
  updateCategory, deleteCategory, partyStart, partyStop, subscribeEvents,
  getSelectedChannels, setSelectedChannel,
} from './api';
import type { VoiceChannelInfo, Sound, Category } from './types';
import { getCookie, setCookie } from './cookies';

/* ── Category Color Palette ── */
const CAT_PALETTE = [
  '#3b82f6', '#f59e0b', '#8b5cf6', '#ec4899', '#14b8a6',
  '#f97316', '#06b6d4', '#ef4444', '#a855f7', '#84cc16',
  '#d946ef', '#0ea5e9', '#f43f5e', '#10b981',
];

const THEMES = [
  { id: 'midnight', label: 'Midnight' },
  { id: 'daylight', label: 'Daylight' },
  { id: 'neon', label: 'Neon' },
  { id: 'vapor', label: 'Vapor' },
  { id: 'matrix', label: 'Matrix' },
];

type Tab = 'all' | 'favorites' | 'recent';

export default function App() {
  /* ── State ── */
  const [sounds, setSounds] = useState<Sound[]>([]);
  const [total, setTotal] = useState(0);
  const [folders, setFolders] = useState<Array<{ key: string; name: string; count: number }>>([]);
  const [categories, setCategories] = useState<Category[]>([]);

  const [activeTab, setActiveTab] = useState<Tab>('all');
  const [activeFolder, setActiveFolder] = useState('');
  const [query, setQuery] = useState('');

  const [channels, setChannels] = useState<VoiceChannelInfo[]>([]);
  const [selected, setSelected] = useState('');
  const selectedRef = useRef('');

  const [volume, setVolume] = useState(1);
  const [favs, setFavs] = useState<Record<string, boolean>>({});
  const [theme, setTheme] = useState(() => localStorage.getItem('jb-theme') || 'midnight');
  const [isAdmin, setIsAdmin] = useState(false);
  const [showAdmin, setShowAdmin] = useState(false);

  const [chaosMode, setChaosMode] = useState(false);
  const [partyActiveGuilds, setPartyActiveGuilds] = useState<string[]>([]);
  const chaosModeRef = useRef(false);

  const [lastPlayed, setLastPlayed] = useState('');
  const [notification, setNotification] = useState<{ msg: string; type: 'info' | 'error' } | null>(null);

  /* ── Refs ── */
  useEffect(() => { chaosModeRef.current = chaosMode; }, [chaosMode]);
  useEffect(() => { selectedRef.current = selected; }, [selected]);

  /* ── Helpers ── */
  const notify = useCallback((msg: string, type: 'info' | 'error' = 'info') => {
    setNotification({ msg, type });
    setTimeout(() => setNotification(null), 3000);
  }, []);

  const guildId = selected ? selected.split(':')[0] : '';
  const channelId = selected ? selected.split(':')[1] : '';

  /* ── Init ── */
  useEffect(() => {
    (async () => {
      try {
        const [ch, selMap] = await Promise.all([fetchChannels(), getSelectedChannels()]);
        setChannels(ch);
        if (ch.length) {
          const g = ch[0].guildId;
          const serverCid = selMap[g];
          const match = serverCid && ch.find(x => x.guildId === g && x.channelId === serverCid);
          setSelected(match ? `${g}:${serverCid}` : `${ch[0].guildId}:${ch[0].channelId}`);
        }
      } catch (e: any) { notify(e?.message || 'Channel-Fehler', 'error'); }
      try { setIsAdmin(await adminStatus()); } catch { }
      try { const c = await fetchCategories(); setCategories(c.categories || []); } catch { }
    })();
  }, []);

  /* ── Theme ── */
  useEffect(() => {
    document.body.setAttribute('data-theme', theme);
    localStorage.setItem('jb-theme', theme);
  }, [theme]);

  /* ── SSE ── */
  useEffect(() => {
    const unsub = subscribeEvents((msg) => {
      if (msg?.type === 'party') {
        setPartyActiveGuilds(prev => {
          const s = new Set(prev);
          if (msg.active) s.add(msg.guildId); else s.delete(msg.guildId);
          return Array.from(s);
        });
      } else if (msg?.type === 'snapshot') {
        setPartyActiveGuilds(Array.isArray(msg.party) ? msg.party : []);
        try {
          const sel = msg?.selected || {};
          const g = selectedRef.current?.split(':')[0];
          if (g && sel[g]) setSelected(`${g}:${sel[g]}`);
        } catch { }
        try {
          const vols = msg?.volumes || {};
          const g = selectedRef.current?.split(':')[0];
          if (g && typeof vols[g] === 'number') setVolume(vols[g]);
        } catch { }
      } else if (msg?.type === 'channel') {
        const g = selectedRef.current?.split(':')[0];
        if (msg.guildId === g) setSelected(`${msg.guildId}:${msg.channelId}`);
      } else if (msg?.type === 'volume') {
        const g = selectedRef.current?.split(':')[0];
        if (msg.guildId === g && typeof msg.volume === 'number') setVolume(msg.volume);
      }
    });
    return () => { try { unsub(); } catch { } };
  }, []);

  useEffect(() => {
    setChaosMode(guildId ? partyActiveGuilds.includes(guildId) : false);
  }, [selected, partyActiveGuilds]);

  /* ── Data Fetch ── */
  useEffect(() => {
    (async () => {
      try {
        let folderParam = '__all__';
        if (activeTab === 'recent') folderParam = '__recent__';
        else if (activeFolder) folderParam = activeFolder;

        const s = await fetchSounds(query, folderParam, undefined, false);
        setSounds(s.items);
        setTotal(s.total);
        setFolders(s.folders);
      } catch (e: any) { notify(e?.message || 'Sounds-Fehler', 'error'); }
    })();
  }, [activeTab, activeFolder, query]);

  /* ── Favs persistence ── */
  useEffect(() => {
    const c = getCookie('favs');
    if (c) try { setFavs(JSON.parse(c)); } catch { }
  }, []);

  useEffect(() => {
    try { setCookie('favs', JSON.stringify(favs)); } catch { }
  }, [favs]);

  /* ── Volume sync ── */
  useEffect(() => {
    if (selected) {
      (async () => {
        try { const v = await getVolume(guildId); setVolume(v); } catch { }
      })();
    }
  }, [selected]);

  /* ── Actions ── */
  async function handlePlay(s: Sound) {
    if (!selected) return notify('Bitte einen Voice-Channel auswählen', 'error');
    try {
      await playSound(s.name, guildId, channelId, volume, s.relativePath);
      setLastPlayed(s.name);
      setTimeout(() => setLastPlayed(''), 4000);
    } catch (e: any) { notify(e?.message || 'Play fehlgeschlagen', 'error'); }
  }

  async function handleStop() {
    if (!selected) return;
    try { await fetch(`/api/stop?guildId=${encodeURIComponent(guildId)}`, { method: 'POST' }); } catch { }
  }

  async function handleRandom() {
    if (!sounds.length || !selected) return;
    const rnd = sounds[Math.floor(Math.random() * sounds.length)];
    handlePlay(rnd);
  }

  async function toggleParty() {
    if (chaosMode) {
      await handleStop();
      try { await partyStop(guildId); } catch { }
    } else {
      if (!selected) return notify('Bitte einen Channel auswählen', 'error');
      try { await partyStart(guildId, channelId); } catch { }
    }
  }

  /* ── Computed ── */
  const displaySounds = useMemo(() => {
    if (activeTab === 'favorites') {
      return sounds.filter(s => favs[s.relativePath ?? s.fileName]);
    }
    return sounds;
  }, [sounds, activeTab, favs]);

  const favCount = useMemo(() => Object.values(favs).filter(Boolean).length, [favs]);

  const visibleFolders = useMemo(() =>
    folders.filter(f => !['__all__', '__recent__', '__top3__'].includes(f.key)),
  [folders]);

  const folderColorMap = useMemo(() => {
    const m: Record<string, string> = {};
    visibleFolders.forEach((f, i) => { m[f.key] = CAT_PALETTE[i % CAT_PALETTE.length]; });
    return m;
  }, [visibleFolders]);

  /* ── Admin State ── */
  const [adminPwd, setAdminPwd] = useState('');

  async function handleAdminLogin() {
    try {
      const ok = await adminLogin(adminPwd);
      if (ok) { setIsAdmin(true); setAdminPwd(''); notify('Admin eingeloggt'); }
      else notify('Falsches Passwort', 'error');
    } catch { notify('Login fehlgeschlagen', 'error'); }
  }

  async function handleAdminLogout() {
    try { await adminLogout(); setIsAdmin(false); notify('Ausgeloggt'); } catch { }
  }

  /* ── Render ── */
  return (
    <div className={`app-shell ${chaosMode ? 'party-active' : ''}`}>

      {/* ════════ Header ════════ */}
      <header className="header">
        <div className="logo">JUKEBOX</div>

        <div className="header-search">
          <span className="material-icons search-icon">search</span>
          <input
            type="text"
            placeholder="Sound suchen..."
            value={query}
            onChange={e => setQuery(e.target.value)}
          />
          {query && (
            <button className="search-clear" onClick={() => setQuery('')}>
              <span className="material-icons" style={{ fontSize: 16 }}>close</span>
            </button>
          )}
        </div>

        <div className="header-meta">
          <div className="sound-count">
            <strong>{total}</strong> Sounds
          </div>

          <select
            className="select-clean"
            value={theme}
            onChange={e => setTheme(e.target.value)}
          >
            {THEMES.map(t => (
              <option key={t.id} value={t.id}>{t.label}</option>
            ))}
          </select>

          <button
            className={`admin-toggle ${isAdmin ? 'is-admin' : ''}`}
            onClick={() => setShowAdmin(true)}
            title="Admin"
          >
            <span className="material-icons" style={{ fontSize: 18 }}>settings</span>
          </button>
        </div>
      </header>

      {/* ════════ Tab Bar ════════ */}
      <nav className="tab-bar">
        <button
          className={`tab-btn ${activeTab === 'all' ? 'active' : ''}`}
          onClick={() => { setActiveTab('all'); setActiveFolder(''); }}
        >
          <span className="material-icons" style={{ fontSize: 16 }}>library_music</span>
          All Sounds
          <span className="tab-badge">{total}</span>
        </button>
        <button
          className={`tab-btn ${activeTab === 'favorites' ? 'active' : ''}`}
          onClick={() => { setActiveTab('favorites'); setActiveFolder(''); }}
        >
          <span className="material-icons" style={{ fontSize: 16 }}>star</span>
          Favorites
          {favCount > 0 && <span className="tab-badge">{favCount}</span>}
        </button>
        <button
          className={`tab-btn ${activeTab === 'recent' ? 'active' : ''}`}
          onClick={() => { setActiveTab('recent'); setActiveFolder(''); }}
        >
          <span className="material-icons" style={{ fontSize: 16 }}>schedule</span>
          Recently Added
        </button>
      </nav>

      {/* ════════ Category Filter ════════ */}
      {activeTab === 'all' && visibleFolders.length > 0 && (
        <div className="category-strip">
          {visibleFolders.map(f => {
            const color = folderColorMap[f.key] || '#888';
            const isActive = activeFolder === f.key;
            return (
              <button
                key={f.key}
                className={`cat-chip ${isActive ? 'active' : ''}`}
                onClick={() => setActiveFolder(isActive ? '' : f.key)}
                style={isActive ? { borderColor: color, color, background: `${color}12` } : undefined}
              >
                <span className="cat-dot" style={{ background: color }} />
                {f.name.replace(/\s*\(\d+\)\s*$/, '')}
                <span style={{ opacity: 0.5, fontSize: 10, fontWeight: 700 }}>{f.count}</span>
              </button>
            );
          })}
        </div>
      )}

      {/* ════════ Sound Grid ════════ */}
      <div className="sounds-area">
        {displaySounds.length === 0 ? (
          <div className="sounds-empty">
            <span className="material-icons">
              {activeTab === 'favorites' ? 'star_border' : 'music_off'}
            </span>
            <p>
              {activeTab === 'favorites'
                ? 'Noch keine Favorites — klick den Stern!'
                : query
                  ? `Kein Sound für "${query}" gefunden`
                  : 'Keine Sounds vorhanden'}
            </p>
          </div>
        ) : (
          <div className="sounds-grid">
            {displaySounds.map((s, idx) => {
              const key = s.relativePath ?? s.fileName;
              const isFav = !!favs[key];
              const color = s.folder ? folderColorMap[s.folder] || '#555' : '#555';
              const isNew = s.badges?.includes('new');
              const isTop = s.badges?.includes('top');
              const isPlaying = lastPlayed === s.name;

              return (
                <button
                  key={key}
                  className={`sound-btn ${isPlaying ? 'is-playing' : ''}`}
                  onClick={() => handlePlay(s)}
                  title={`${s.name}${s.folder ? ` (${s.folder})` : ''}`}
                  style={{ animationDelay: `${Math.min(idx * 8, 400)}ms` }}
                >
                  <span className="cat-bar" style={{ background: color }} />
                  <span className="sound-label">{s.name}</span>

                  {isNew && <span className="badge-dot new" />}
                  {isTop && !isNew && <span className="badge-dot top" />}

                  <span
                    className={`fav-star ${isFav ? 'is-fav' : ''}`}
                    onClick={e => {
                      e.stopPropagation();
                      setFavs(prev => ({ ...prev, [key]: !prev[key] }));
                    }}
                  >
                    <span className="material-icons" style={{ fontSize: 14 }}>
                      {isFav ? 'star' : 'star_border'}
                    </span>
                  </span>
                </button>
              );
            })}
          </div>
        )}
      </div>

      {/* ════════ Control Bar ════════ */}
      <div className="control-bar">
        <div className="ctrl-section left">
          <div className="channel-wrap">
            <span className="material-icons">headset_mic</span>
            <select
              className="channel-select"
              value={selected}
              onChange={async e => {
                const v = e.target.value;
                setSelected(v);
                try {
                  const [g, c] = v.split(':');
                  await setSelectedChannel(g, c);
                } catch { }
              }}
            >
              <option value="" disabled>Channel...</option>
              {channels.map(c => (
                <option key={`${c.guildId}:${c.channelId}`} value={`${c.guildId}:${c.channelId}`}>
                  {c.guildName} · {c.channelName}
                </option>
              ))}
            </select>
          </div>

          {lastPlayed && (
            <div className="now-playing">
              <span className="material-icons" style={{ fontSize: 14, verticalAlign: -2, marginRight: 4 }}>play_arrow</span>
              <span>{lastPlayed}</span>
            </div>
          )}
        </div>

        <div className="ctrl-section center">
          <button className="ctrl-btn stop" onClick={handleStop} title="Stop">
            <span className="material-icons">stop</span>
            <span>Stop</span>
          </button>

          <button className="ctrl-btn shuffle" onClick={handleRandom} title="Zufälliger Sound">
            <span className="material-icons">shuffle</span>
            <span>Random</span>
          </button>

          <button
            className={`ctrl-btn party ${chaosMode ? 'active' : ''}`}
            onClick={toggleParty}
            title="Partymode"
          >
            <span className="material-icons">{chaosMode ? 'celebration' : 'auto_awesome'}</span>
            <span>{chaosMode ? 'Party!' : 'Party'}</span>
          </button>
        </div>

        <div className="ctrl-section right">
          <div className="volume-wrap">
            <span
              className="material-icons"
              onClick={() => {
                const newVol = volume > 0 ? 0 : 0.5;
                setVolume(newVol);
                if (guildId) setVolumeLive(guildId, newVol).catch(() => {});
              }}
            >
              {volume === 0 ? 'volume_off' : volume < 0.5 ? 'volume_down' : 'volume_up'}
            </span>
            <input
              className="volume-slider"
              type="range"
              min={0} max={1} step={0.01}
              value={volume}
              onChange={async e => {
                const v = parseFloat(e.target.value);
                setVolume(v);
                if (guildId) try { await setVolumeLive(guildId, v); } catch { }
              }}
              style={{ '--fill': `${Math.round(volume * 100)}%` } as React.CSSProperties}
            />
            <span className="volume-pct">{Math.round(volume * 100)}%</span>
          </div>
        </div>
      </div>

      {/* ════════ Notification Toast ════════ */}
      {notification && (
        <div className={`toast ${notification.type}`}>
          <span className="material-icons" style={{ fontSize: 16 }}>
            {notification.type === 'error' ? 'error_outline' : 'check_circle'}
          </span>
          {notification.msg}
        </div>
      )}

      {/* ════════ Admin Panel Overlay ════════ */}
      {showAdmin && (
        <div className="admin-overlay" onClick={e => { if (e.target === e.currentTarget) setShowAdmin(false); }}>
          <div className="admin-panel">
            <h3>
              Admin
              <button className="admin-close" onClick={() => setShowAdmin(false)}>
                <span className="material-icons" style={{ fontSize: 18 }}>close</span>
              </button>
            </h3>

            {!isAdmin ? (
              <div>
                <div className="admin-field">
                  <label>Password</label>
                  <input
                    type="password"
                    value={adminPwd}
                    onChange={e => setAdminPwd(e.target.value)}
                    onKeyDown={e => e.key === 'Enter' && handleAdminLogin()}
                    placeholder="Admin-Passwort..."
                  />
                </div>
                <button className="admin-btn primary" onClick={handleAdminLogin}>
                  Login
                </button>
              </div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                <p style={{ fontSize: 13, color: 'var(--text-secondary)' }}>
                  Eingeloggt als Admin
                </p>
                <button className="admin-btn outline" onClick={handleAdminLogout}>
                  Logout
                </button>
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}
