import { useState, useEffect, useMemo } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import { Search, Plus, GitCompare, Pin, Trash2, X, Play, ArrowUp, ArrowDown, GitMerge, Pencil } from 'lucide-react';
import { experimentsApi, type ExperimentMeta } from '../api/client';
import { Loading, ErrorState } from '../components/common/Loading';
import { StatusBadge } from '../components/common/StatusBadge';
import { fmt } from '../lib/utils';

const STATUS_OPTS = ['', 'promoted', 'active', 'draft', 'retired', 'archived'];


function ExpRow({
  exp,
  onClick,
  selected,
  onToggle,
  onPin,
  onDelete,
  onRun,
  onEdit,
}: {
  exp: ExperimentMeta;
  onClick: () => void;
  selected: boolean;
  onToggle: (e: React.MouseEvent) => void;
  onPin: (e: React.MouseEvent) => void;
  onDelete: (e: React.MouseEvent) => void;
  onRun: (e: React.MouseEvent) => void;
  onEdit: (e: React.MouseEvent) => void;
}) {
  const isPinned = exp.status === 'promoted';

  return (
    <tr
      style={{
        borderBottom: '1px solid var(--border)',
        background: selected ? 'var(--cyan-dim)' : 'transparent',
        transition: 'background 0.1s',
      }}
    >
      {/* Checkbox */}
      <td style={{ padding: '10px 8px 10px 16px', width: 36 }} onClick={onToggle}>
        <input
          type="checkbox"
          checked={selected}
          onChange={() => {}}
          style={{ width: 15, height: 15, cursor: 'pointer', accentColor: 'var(--cyan)' }}
        />
      </td>
      <td
        style={{ padding: '10px 14px', fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text3)', width: 44, textAlign: 'right', cursor: 'pointer' }}
        onClick={onClick}
      >
        {exp.id ?? '—'}
      </td>
      <td style={{ padding: '10px 8px 10px 0', cursor: 'pointer' }} onClick={onClick}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          {isPinned && <Pin size={13} style={{ color: 'var(--green)', flexShrink: 0 }} />}
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 15, color: 'var(--text1)' }}>
            {exp.name}
          </span>
          {exp.aliases?.map(a => (
            <span key={a} style={{
              fontSize: 12, fontFamily: 'var(--font-mono)',
              background: 'var(--purple-dim)', color: 'var(--purple)',
              border: '1px solid rgba(124,58,237,0.18)',
              padding: '1px 6px', borderRadius: 4, letterSpacing: '0.03em',
            }}>
              {a}
            </span>
          ))}
        </div>
      </td>
      <td style={{ padding: '10px 12px', cursor: 'pointer' }} onClick={onClick}>
        <StatusBadge status={exp.status} />
      </td>
      <td style={{ padding: '10px 12px', fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--cyan)', cursor: 'pointer' }} onClick={onClick}>
        {exp.version_family ?? '—'}
      </td>
      <td style={{ padding: '10px 12px', fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text3)', cursor: 'pointer' }} onClick={onClick}>
        {exp.generation != null ? `gen ${exp.generation}` : '—'}
      </td>
      <td style={{ padding: '10px 12px', cursor: 'pointer' }} onClick={onClick}>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 3, maxWidth: 240 }}>
          {exp.tags?.slice(0, 3).map(t => (
            <span key={t} style={{
              fontSize: 12, fontFamily: 'var(--font-mono)',
              background: 'var(--bg2)', color: 'var(--text3)',
              border: '1px solid var(--border-md)', padding: '1px 6px', borderRadius: 4,
            }}>
              {t}
            </span>
          ))}
          {(exp.tags?.length ?? 0) > 3 && (
            <span style={{ fontSize: 12, color: 'var(--text3)' }}>+{exp.tags!.length - 3}</span>
          )}
        </div>
      </td>
      <td style={{ padding: '10px 14px', textAlign: 'right', cursor: 'pointer' }} onClick={onClick}>
        {exp.sqs_score != null ? (
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 15, fontWeight: 600,
            color: exp.sqs_score >= 70 ? 'var(--green)' : exp.sqs_score >= 55 ? 'var(--cyan)' : 'var(--gold)',
          }}>
            {fmt(exp.sqs_score)}
          </span>
        ) : (
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text3)' }}>—</span>
        )}
      </td>
      {/* Inline action buttons — visible on hover */}
      <td style={{ padding: '10px 14px', width: 124 }}>
        <div style={{ display: 'flex', gap: 4 }}>
          <button
            onClick={onEdit}
            title="Edit"
            style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              width: 28, height: 28, borderRadius: 6, border: '1px solid var(--border-md)',
              background: 'none', color: 'var(--text3)', cursor: 'pointer',
            }}
            onMouseEnter={e => { (e.currentTarget as HTMLButtonElement).style.color = 'var(--cyan)'; (e.currentTarget as HTMLButtonElement).style.borderColor = 'rgba(0,119,182,0.3)'; }}
            onMouseLeave={e => { (e.currentTarget as HTMLButtonElement).style.color = 'var(--text3)'; (e.currentTarget as HTMLButtonElement).style.borderColor = 'var(--border-md)'; }}
          >
            <Pencil size={13} />
          </button>
          <button
            onClick={onRun}
            title="Run Backtest"
            style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              width: 28, height: 28, borderRadius: 6, border: '1px solid var(--border-md)',
              background: 'none', color: 'var(--text3)', cursor: 'pointer',
            }}
            onMouseEnter={e => { (e.currentTarget as HTMLButtonElement).style.color = 'var(--orange)'; (e.currentTarget as HTMLButtonElement).style.borderColor = 'rgba(234,88,12,0.3)'; }}
            onMouseLeave={e => { (e.currentTarget as HTMLButtonElement).style.color = 'var(--text3)'; (e.currentTarget as HTMLButtonElement).style.borderColor = 'var(--border-md)'; }}
          >
            <Play size={13} />
          </button>
          <button
            onClick={onPin}
            title={isPinned ? 'Unpin' : 'Pin'}
            style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              width: 28, height: 28, borderRadius: 6, border: '1px solid var(--border-md)',
              background: isPinned ? 'var(--green-dim)' : 'none',
              color: isPinned ? 'var(--green)' : 'var(--text3)', cursor: 'pointer',
            }}
          >
            <Pin size={13} />
          </button>
          <button
            onClick={onDelete}
            title="Delete"
            style={{
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              width: 28, height: 28, borderRadius: 6, border: '1px solid var(--border-md)',
              background: 'none', color: 'var(--text3)', cursor: 'pointer',
            }}
            onMouseEnter={e => { (e.currentTarget as HTMLButtonElement).style.color = 'var(--red)'; (e.currentTarget as HTMLButtonElement).style.borderColor = 'rgba(220,38,38,0.3)'; }}
            onMouseLeave={e => { (e.currentTarget as HTMLButtonElement).style.color = 'var(--text3)'; (e.currentTarget as HTMLButtonElement).style.borderColor = 'var(--border-md)'; }}
          >
            <Trash2 size={13} />
          </button>
        </div>
      </td>
    </tr>
  );
}

export function ExperimentsPage() {
  const navigate = useNavigate();
  const qc = useQueryClient();
  const [search, setSearch] = useState('');
  const [status, setStatus] = useState('');
  const [family, setFamily] = useState('');
  const [includeRetired, setIncludeRetired] = useState(false);
  const [debouncedSearch, setDebouncedSearch] = useState('');
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [sortKey, setSortKey] = useState<'sqs' | 'id'>(() => {
    return (localStorage.getItem('exp_sort_key') as 'sqs' | 'id') ?? 'id';
  });
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>(() => {
    return (localStorage.getItem('exp_sort_dir') as 'asc' | 'desc') ?? 'desc';
  });

  useEffect(() => {
    const t = setTimeout(() => setDebouncedSearch(search), 280);
    return () => clearTimeout(t);
  }, [search]);

  const { data, isLoading, error } = useQuery({
    queryKey: ['experiments', debouncedSearch, status, family, includeRetired],
    queryFn: () => experimentsApi.list({
      pattern: debouncedSearch || undefined,
      status: status || undefined,
      family: family || undefined,
      include_retired: includeRetired,
      sort_by: 'sqs',
      limit: 500,
    }),
  });

  const { data: familiesData } = useQuery({
    queryKey: ['experiment-families'],
    queryFn: experimentsApi.families,
    staleTime: 60_000,
  });

  const deleteMutation = useMutation({
    mutationFn: async (names: string[]) => {
      for (const n of names) await experimentsApi.delete(n);
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['experiments'] });
      setSelected(new Set());
    },
  });

  const sortedExps = useMemo(() => {
    if (!data) return [];
    return [...data.experiments].sort((a, b) => {
      const aPinned = a.status === 'promoted' ? 0 : 1;
      const bPinned = b.status === 'promoted' ? 0 : 1;
      if (aPinned !== bPinned) return aPinned - bPinned;
      const dir = sortDir === 'desc' ? -1 : 1;
      if (sortKey === 'id') {
        if (a.id == null && b.id == null) return 0;
        if (a.id == null) return 1;
        if (b.id == null) return -1;
        return (a.id - b.id) * dir;
      }
      // sqs
      if (a.sqs_score == null && b.sqs_score == null) return 0;
      if (a.sqs_score == null) return 1;
      if (b.sqs_score == null) return -1;
      return (a.sqs_score - b.sqs_score) * dir;
    });
  }, [data, sortKey, sortDir]);

  const allNames = sortedExps.map(e => e.name);
  const allSelected = allNames.length > 0 && selected.size === allNames.length;

  const toggleAll = () => {
    setSelected(allSelected ? new Set() : new Set(allNames));
  };

  const toggleOne = (name: string, e: React.MouseEvent) => {
    e.stopPropagation();
    setSelected(prev => {
      const next = new Set(prev);
      next.has(name) ? next.delete(name) : next.add(name);
      return next;
    });
  };

  const handleDelete = () => {
    const names = [...selected];
    if (!window.confirm(`${names.length}개 전략을 삭제하시겠습니까?\n\n${names.join('\n')}`)) return;
    deleteMutation.mutate(names);
  };

  const handleCompare = () => {
    const [a, b] = [...selected];
    navigate(`/experiments/${encodeURIComponent(a)}/diff/${encodeURIComponent(b)}`);
  };

  const handlePinOne = (name: string, isPinned: boolean) => {
    const newStatus = isPinned ? 'active' : 'promoted';
    experimentsApi.setStatus(name, newStatus).then(() => qc.invalidateQueries({ queryKey: ['experiments'] }));
  };

  const handleDeleteOne = (name: string) => {
    if (!window.confirm(`전략 "${name}"을(를) 삭제하시겠습니까?`)) return;
    experimentsApi.delete(name).then(() => qc.invalidateQueries({ queryKey: ['experiments'] }));
  };

  const handleRunSelected = () => {
    navigate(`/backtest?exp=${[...selected].map(encodeURIComponent).join(',')}`);
  };

  return (
    <div style={{ padding: '36px 40px' }} className="fade-up">
      {/* Header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 24 }}>
        <div>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, letterSpacing: '0.10em', color: 'var(--text3)', textTransform: 'uppercase', marginBottom: 5 }}>
            {data ? `${data.total} total` : ''}
          </div>
          <h1 style={{ fontSize: 28, fontWeight: 700, color: 'var(--text1)', letterSpacing: '-0.02em' }}>Strategies</h1>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button
            onClick={() => navigate('/experiments/compose')}
            style={{
              display: 'flex', alignItems: 'center', gap: 6,
              padding: '8px 16px',
              background: 'color-mix(in srgb, var(--cyan) 8%, transparent)',
              border: '1px solid rgba(0,119,182,0.2)',
              borderRadius: 8, color: 'var(--cyan)', fontSize: 14, fontWeight: 500, cursor: 'pointer', transition: 'all 0.12s',
            }}
            onMouseEnter={e => ((e.currentTarget as HTMLButtonElement).style.background = 'var(--cyan-dim)')}
            onMouseLeave={e => ((e.currentTarget as HTMLButtonElement).style.background = 'color-mix(in srgb, var(--cyan) 8%, transparent)')}
          >
            <GitMerge size={14} /> Compose
          </button>
          <button
            onClick={() => navigate('/experiments/new')}
            style={{
              display: 'flex', alignItems: 'center', gap: 6,
              padding: '8px 16px',
              background: 'var(--cyan-dim)', border: '1px solid rgba(0,119,182,0.25)',
              borderRadius: 8, color: 'var(--cyan)', fontSize: 14, fontWeight: 500, cursor: 'pointer', transition: 'all 0.12s',
            }}
            onMouseEnter={e => ((e.currentTarget as HTMLButtonElement).style.background = 'var(--cyan-mid)')}
            onMouseLeave={e => ((e.currentTarget as HTMLButtonElement).style.background = 'var(--cyan-dim)')}
          >
            <Plus size={14} /> New
          </button>
        </div>
      </div>

      {/* Filters + inline selection actions */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 18, flexWrap: 'wrap', alignItems: 'center' }}>
        <div style={{ position: 'relative' }}>
          <Search size={13} style={{ position: 'absolute', left: 11, top: '50%', transform: 'translateY(-50%)', color: 'var(--text3)', pointerEvents: 'none' }} />
          <input
            type="text"
            placeholder="Search strategies..."
            value={search}
            onChange={e => setSearch(e.target.value)}
            style={{ paddingLeft: 34, paddingRight: search ? 28 : 10, width: 240 }}
          />
          {search && (
            <button
              onClick={() => setSearch('')}
              style={{
                position: 'absolute', right: 7, top: '50%', transform: 'translateY(-50%)',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                width: 16, height: 16, borderRadius: '50%',
                background: 'var(--text3)', border: 'none', cursor: 'pointer', padding: 0,
                opacity: 0.6,
              }}
              onMouseEnter={e => ((e.currentTarget as HTMLButtonElement).style.opacity = '1')}
              onMouseLeave={e => ((e.currentTarget as HTMLButtonElement).style.opacity = '0.6')}
            >
              <X size={10} style={{ color: 'var(--bg0)' }} />
            </button>
          )}
        </div>
        <select value={status} onChange={e => setStatus(e.target.value)} style={{ minWidth: 130 }}>
          <option value="">All statuses</option>
          {STATUS_OPTS.filter(Boolean).map(s => (
            <option key={s} value={s}>{s === 'promoted' ? 'pinned' : s}</option>
          ))}
        </select>
        <select value={family} onChange={e => setFamily(e.target.value)} style={{ minWidth: 110 }}>
          <option value="">All families</option>
          {familiesData?.families.map(f => <option key={f} value={f}>{f}</option>)}
        </select>
        <label style={{ display: 'flex', alignItems: 'center', gap: 7, fontSize: 13, color: 'var(--text3)', cursor: 'pointer', fontFamily: 'var(--font-mono)', userSelect: 'none' }}>
          <input
            type="checkbox"
            checked={includeRetired}
            onChange={e => setIncludeRetired(e.target.checked)}
            style={{ width: 14, height: 14, accentColor: 'var(--cyan)' }}
          />
          retired
        </label>

        {selected.size > 0 && (
          <>
            <div style={{ width: 1, height: 24, background: 'var(--border-md)', flexShrink: 0 }} />
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text3)' }}>
              {selected.size} selected
            </span>
            <button onClick={handleRunSelected} style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '5px 12px', borderRadius: 6, fontSize: 13, fontWeight: 500, background: 'color-mix(in srgb, var(--orange) 10%, transparent)', border: '1px solid rgba(234,88,12,0.25)', color: 'var(--orange)', cursor: 'pointer' }}>
              <Play size={13} /> Run
            </button>
            {selected.size === 2 && (
              <button onClick={handleCompare} style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '5px 12px', borderRadius: 6, fontSize: 13, fontWeight: 500, background: 'var(--cyan-dim)', border: '1px solid rgba(0,119,182,0.25)', color: 'var(--cyan)', cursor: 'pointer' }}>
                <GitCompare size={13} /> Compare
              </button>
            )}
            <button onClick={handleDelete} disabled={deleteMutation.isPending} style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '5px 12px', borderRadius: 6, fontSize: 13, fontWeight: 500, background: 'var(--red-dim)', border: '1px solid rgba(220,38,38,0.22)', color: 'var(--red)', cursor: 'pointer', opacity: deleteMutation.isPending ? 0.6 : 1 }}>
              <Trash2 size={13} /> {deleteMutation.isPending ? 'Deleting...' : 'Delete'}
            </button>
            <button onClick={() => setSelected(new Set())} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 26, height: 26, borderRadius: 5, background: 'none', border: '1px solid var(--border-md)', color: 'var(--text3)', cursor: 'pointer' }}>
              <X size={13} />
            </button>
          </>
        )}
      </div>

      {isLoading && <Loading />}
      {error && <ErrorState error={error as Error} />}

      {data && (
        <div style={{ background: 'var(--bg1)', border: '1px solid var(--border)', borderRadius: 12, overflow: 'hidden', boxShadow: '0 1px 3px rgba(0,0,0,0.04)' }}>
          <div style={{ overflowX: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse' }}>
              <thead>
                <tr style={{ borderBottom: '1px solid var(--border-md)', background: 'var(--bg2)' }}>
                  {/* Select all checkbox */}
                  <th style={{ padding: '11px 8px 11px 16px', width: 36 }}>
                    <input
                      type="checkbox"
                      checked={allSelected}
                      onChange={toggleAll}
                      style={{ width: 15, height: 15, cursor: 'pointer', accentColor: 'var(--cyan)' }}
                    />
                  </th>
                  {['ID', 'Name', 'Status', 'Family', 'Gen', 'Tags', 'SQS', 'Actions'].map((h, i) => {
                    const isSortable = h === 'ID' || h === 'SQS';
                    const key = h === 'ID' ? 'id' : 'sqs';
                    const isActive = isSortable && sortKey === key;
                    return (
                      <th
                        key={h}
                        onClick={isSortable ? () => {
                          const k = key as 'id' | 'sqs';
                          if (sortKey === k) {
                            const d = sortDir === 'desc' ? 'asc' : 'desc';
                            setSortDir(d);
                            localStorage.setItem('exp_sort_dir', d);
                          } else {
                            setSortKey(k);
                            setSortDir('desc');
                            localStorage.setItem('exp_sort_key', k);
                            localStorage.setItem('exp_sort_dir', 'desc');
                          }
                        } : undefined}
                        style={{
                          padding: '11px 14px',
                          textAlign: i === 6 ? 'right' : 'left',
                          fontFamily: 'var(--font-mono)',
                          fontSize: 12, fontWeight: 500, letterSpacing: '0.07em',
                          textTransform: 'uppercase',
                          color: isActive ? 'var(--cyan)' : 'var(--text3)',
                          whiteSpace: 'nowrap',
                          cursor: isSortable ? 'pointer' : 'default',
                          userSelect: 'none',
                        }}
                      >
                        <div style={{ display: 'flex', alignItems: 'center', gap: 4, justifyContent: i === 6 ? 'flex-end' : 'flex-start' }}>
                          {h}
                          {isActive && (sortDir === 'desc' ? <ArrowDown size={11} /> : <ArrowUp size={11} />)}
                          {isSortable && !isActive && <ArrowUp size={11} style={{ opacity: 0.3 }} />}
                        </div>
                      </th>
                    );
                  })}
                </tr>
              </thead>
              <tbody>
                {sortedExps.map(exp => (
                  <ExpRow
                    key={exp.name}
                    exp={exp}
                    selected={selected.has(exp.name)}
                    onToggle={e => toggleOne(exp.name, e)}
                    onClick={() => navigate(`/experiments/${encodeURIComponent(exp.name)}`)}
                    onPin={e => { e.stopPropagation(); handlePinOne(exp.name, exp.status === 'promoted'); }}
                    onDelete={e => { e.stopPropagation(); handleDeleteOne(exp.name); }}
                    onRun={e => { e.stopPropagation(); navigate(`/backtest?exp=${encodeURIComponent(exp.name)}`); }}
                    onEdit={e => { e.stopPropagation(); navigate(`/experiments/${encodeURIComponent(exp.name)}?edit=true`); }}
                  />
                ))}
                {sortedExps.length === 0 && (
                  <tr>
                    <td colSpan={9} style={{ padding: '56px 0', textAlign: 'center', color: 'var(--text3)', fontFamily: 'var(--font-mono)', fontSize: 15 }}>
                      no strategies found
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </div>
      )}

    </div>
  );
}
