import React, { useRef, useState } from 'react';
import type { EditorStore } from '../../store/editorStore';
import type { CBNode, JalpiClass } from '../../types';
import { useApi } from '../../hooks/useApi';

interface Props {
  store: EditorStore;
  api: ReturnType<typeof useApi>;
  onToast: (msg: string) => void;
}

// Count how many nodes on the CURRENT page have this class attached — an
// instant, always-fresh local number. Full site-wide usage (across every
// page) is fetched on demand only when the delete-confirmation dialog opens,
// via GET /classes/{key}/usage — see openDeleteConfirm() below.
function countUsageOnPage(sections: CBNode[], key: string): number {
  let count = 0;
  const walk = (nodes: CBNode[]) => {
    for (const n of nodes) {
      const attached = (n.settings as { cssClasses?: string[] } | undefined)?.cssClasses ?? [];
      if (attached.includes(key)) count++;
      if (n.children?.length) walk(n.children);
    }
  };
  walk(sections);
  return count;
}

export function ClassesPanel({ store, api, onToast }: Props) {
  const { state } = store;
  const [search, setSearch] = useState('');
  const [favoriteOnly, setFavoriteOnly] = useState(false);
  const [newName, setNewName] = useState('');
  const [renamingKey, setRenamingKey] = useState<string | null>(null);
  const [renameValue, setRenameValue] = useState('');
  const [confirmDeleteKey, setConfirmDeleteKey] = useState<string | null>(null);
  const [deleteUsage, setDeleteUsage] = useState<number | null>(null);
  const importInputRef = useRef<HTMLInputElement>(null);

  // Initial fetch happens once in App.tsx (mount) so state.classes is ready
  // before this panel is ever opened — the PropertiesPanel class picker
  // needs it too, regardless of which inspector tab is active.

  const filtered = state.classes.filter((c) => {
    if (favoriteOnly && !c.favorite) return false;
    if (search && !c.name.toLowerCase().includes(search.toLowerCase())) return false;
    return true;
  });

  const handleCreate = async () => {
    const name = newName.trim();
    if (!name) return;
    try {
      const created = await api.createClass(name);
      store.upsertClass(created);
      setNewName('');
      store.setEditingClassKey(created.key);
      onToast(`Class "${created.name}" created`);
    } catch (err) {
      onToast(err instanceof Error ? err.message : 'Could not create class');
    }
  };

  const commitRename = async (key: string) => {
    const name = renameValue.trim();
    setRenamingKey(null);
    if (!name) return;
    try {
      const updated = await api.updateClass(key, { name });
      store.upsertClass(updated);
    } catch (err) {
      onToast(err instanceof Error ? err.message : 'Rename failed');
    }
  };

  const handleDuplicate = async (key: string) => {
    try {
      const dup = await api.duplicateClass(key);
      store.upsertClass(dup);
      onToast(`Duplicated as "${dup.name}"`);
    } catch (err) {
      onToast(err instanceof Error ? err.message : 'Duplicate failed');
    }
  };

  const handleToggleFavorite = async (key: string) => {
    try {
      const updated = await api.toggleFavoriteClass(key);
      store.upsertClass(updated);
    } catch (err) {
      onToast(err instanceof Error ? err.message : 'Could not update favorite');
    }
  };

  const openDeleteConfirm = (key: string) => {
    setConfirmDeleteKey(key);
    setDeleteUsage(null);
    api.getClassUsage(key)
      .then((res) => setDeleteUsage(res.count))
      .catch(() => setDeleteUsage(0));
  };

  const handleDelete = async (key: string) => {
    try {
      await api.deleteClass(key);
      store.removeClassFromStore(key);
      if (state.editingClassKey === key) store.setEditingClassKey(null);
      onToast('Class deleted');
    } catch (err) {
      onToast(err instanceof Error ? err.message : 'Delete failed');
    } finally {
      setConfirmDeleteKey(null);
    }
  };

  const moveClass = async (key: string, direction: 'up' | 'down') => {
    const idx = state.classes.findIndex((c) => c.key === key);
    if (idx === -1) return;
    const swapIdx = direction === 'up' ? idx - 1 : idx + 1;
    if (swapIdx < 0 || swapIdx >= state.classes.length) return;
    const keys = state.classes.map((c) => c.key);
    [keys[idx], keys[swapIdx]] = [keys[swapIdx], keys[idx]];
    store.setClassesOrder(keys);
    try {
      await api.reorderClasses(keys);
    } catch {
      onToast('Could not save class order');
    }
  };

  const handleExport = async () => {
    try {
      const data = await api.exportClasses();
      const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'jalpi-classes.json';
      a.click();
      URL.revokeObjectURL(url);
    } catch (err) {
      onToast(err instanceof Error ? err.message : 'Export failed');
    }
  };

  const handleImportFile = async (file: File) => {
    try {
      const text = await file.text();
      const parsed = JSON.parse(text);
      const classes: JalpiClass[] = Array.isArray(parsed) ? parsed : (parsed.classes ?? []);
      if (!classes.length) {
        onToast('No classes found in that file');
        return;
      }
      const result = await api.importClasses(classes, 'skip');
      const fresh = await api.getClasses();
      store.setClasses(fresh);
      onToast(`Imported — ${result.created} created, ${result.updated} updated, ${result.skipped} skipped`);
    } catch (err) {
      onToast(err instanceof Error ? err.message : 'Import failed — invalid file');
    }
  };

  return (
    <div className="jalpi-classes-panel">
      <p className="jalpi-classes-panel__hint">
        Reusable, site-wide classes — attach one to unlimited widgets, edit it once to update every widget it's on.
        List order below breaks ties when an element has more than one class.
      </p>

      <div className="jalpi-classes-panel__toolbar">
        <input
          type="text"
          className="jalpi-classes-panel__search"
          placeholder="Search classes…"
          value={search}
          onChange={(e) => setSearch(e.target.value)}
        />
        <button
          type="button"
          className={`jalpi-classes-panel__fav-filter${favoriteOnly ? ' is-active' : ''}`}
          onClick={() => setFavoriteOnly((v) => !v)}
          title="Show favorites only"
        >
          <StarIcon filled={favoriteOnly} />
        </button>
      </div>

      <div className="jalpi-classes-panel__create">
        <input
          type="text"
          placeholder="New class name…"
          value={newName}
          onChange={(e) => setNewName(e.target.value)}
          onKeyDown={(e) => { if (e.key === 'Enter') handleCreate(); }}
        />
        <button type="button" className="jalpi-btn jalpi-btn--teal" onClick={handleCreate}>+ New Class</button>
      </div>

      {!state.classesLoaded && <div className="jalpi-classes-panel__loading">Loading…</div>}

      {state.classesLoaded && filtered.length === 0 && (
        <div className="jalpi-classes-panel__empty">
          {state.classes.length === 0 ? 'No classes yet — create one above.' : 'No classes match your search.'}
        </div>
      )}

      <ul className="jalpi-classes-panel__list">
        {filtered.map((cls, i) => (
          <li
            key={cls.key}
            className={`jalpi-classes-panel__row${state.editingClassKey === cls.key ? ' is-editing' : ''}`}
          >
            <button
              type="button"
              className="jalpi-classes-panel__fav"
              onClick={() => handleToggleFavorite(cls.key)}
              title={cls.favorite ? 'Unfavorite' : 'Favorite'}
            >
              <StarIcon filled={cls.favorite} />
            </button>

            {renamingKey === cls.key ? (
              <input
                type="text"
                autoFocus
                className="jalpi-classes-panel__rename-input"
                value={renameValue}
                onChange={(e) => setRenameValue(e.target.value)}
                onBlur={() => commitRename(cls.key)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') commitRename(cls.key);
                  if (e.key === 'Escape') setRenamingKey(null);
                }}
              />
            ) : (
              <button
                type="button"
                className="jalpi-classes-panel__name"
                onDoubleClick={() => { setRenamingKey(cls.key); setRenameValue(cls.name); }}
                onClick={() => store.setEditingClassKey(cls.key)}
                title="Click to edit its styles in the Style tab · double-click to rename"
              >
                .{cls.name}
              </button>
            )}

            <span className="jalpi-classes-panel__usage" title="Used on the current page">
              {countUsageOnPage(state.pageData.sections, cls.key)}×
            </span>

            <div className="jalpi-classes-panel__row-actions">
              <button type="button" disabled={i === 0} onClick={() => moveClass(cls.key, 'up')} title="Move up (higher cascade priority)">
                <ChevronIcon dir="up" />
              </button>
              <button type="button" disabled={i === filtered.length - 1} onClick={() => moveClass(cls.key, 'down')} title="Move down">
                <ChevronIcon dir="down" />
              </button>
              <button type="button" onClick={() => handleDuplicate(cls.key)} title="Duplicate">
                <DuplicateIcon />
              </button>
              <button type="button" onClick={() => openDeleteConfirm(cls.key)} title="Delete">
                <DeleteIcon />
              </button>
            </div>
          </li>
        ))}
      </ul>

      <div className="jalpi-classes-panel__footer">
        <button type="button" onClick={handleExport}>Export</button>
        <button type="button" onClick={() => importInputRef.current?.click()}>Import</button>
        <input
          ref={importInputRef}
          type="file"
          accept="application/json"
          style={{ display: 'none' }}
          onChange={(e) => {
            const file = e.target.files?.[0];
            if (file) handleImportFile(file);
            e.target.value = '';
          }}
        />
      </div>

      {confirmDeleteKey && (
        <div className="jalpi-modal-overlay" onClick={() => setConfirmDeleteKey(null)}>
          <div className="jalpi-modal" onClick={(e) => e.stopPropagation()}>
            <h3>Delete class?</h3>
            <p>
              {deleteUsage === null
                ? 'Checking usage…'
                : deleteUsage > 0
                  ? `This class is referenced on ${deleteUsage} page(s) site-wide. Deleting it removes its styling from every widget it's attached to.`
                  : 'This class is not currently used on any saved page.'}
            </p>
            <div className="jalpi-modal__actions">
              <button type="button" onClick={() => setConfirmDeleteKey(null)}>Cancel</button>
              <button type="button" className="jalpi-btn--danger" onClick={() => handleDelete(confirmDeleteKey)}>Delete</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function StarIcon({ filled }: { filled: boolean }) {
  return (
    <svg width="13" height="13" viewBox="0 0 24 24" fill={filled ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
    </svg>
  );
}

function DuplicateIcon() {
  return (
    <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <rect x="8" y="8" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
    </svg>
  );
}

function DeleteIcon() {
  return (
    <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <polyline points="3 6 5 6 21 6" /><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
    </svg>
  );
}

function ChevronIcon({ dir }: { dir: 'up' | 'down' }) {
  return (
    <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
      {dir === 'up' ? <polyline points="18 15 12 9 6 15" /> : <polyline points="6 9 12 15 18 9" />}
    </svg>
  );
}
