import React, { useEffect, useMemo, useRef, useState } from 'react';
import { ChipsInput } from './ChipsInput.jsx';
import { isValidCidr, isValidPort, ruleErrors, hasErrors } from '../utils/validation.js';
import { api } from '../api.js';

const DOMAIN = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i;
const RULE_SET_TAG = /^[a-z0-9][a-z0-9_.@!-]*$/i;
const validDomain = (v) => DOMAIN.test(String(v).trim());
const validRuleSetTag = (v) => RULE_SET_TAG.test(String(v).trim());

const RS_PAGE_SIZE = 100;
const RS_TYPE_LABELS = { domain: 'домен', suffix: 'суффикс', keyword: 'ключ', cidr: 'CIDR', regex: 'regex' };

function RuleSetBrowseModal({ tag, url, rule, onPatch, onClose }) {
  const [status, setStatus] = useState('loading');
  const [data, setData] = useState(null);
  const [error, setError] = useState('');
  const [search, setSearch] = useState('');
  const [typeFilter, setTypeFilter] = useState('all');
  const [page, setPage] = useState(0);
  const inputRef = useRef(null);

  useEffect(() => {
    api.ruleSets.lookup(tag, url)
      .then((d) => { setData(d); setStatus('done'); })
      .catch((err) => { setError(err.message); setStatus('error'); });
  }, [tag, url]);

  useEffect(() => {
    if (status === 'done') setTimeout(() => inputRef.current?.focus(), 50);
  }, [status]);

  const filtered = useMemo(() => {
    if (!data?.entries) return [];
    const q = search.trim().toLowerCase();
    return data.entries.filter((e) => {
      if (typeFilter !== 'all' && e.type !== typeFilter) return false;
      if (!q) return true;
      return e.value.toLowerCase().includes(q);
    });
  }, [data, search, typeFilter]);

  function onSearchChange(v) { setSearch(v); setPage(0); }
  function onTypeChange(v) { setTypeFilter(v); setPage(0); }

  function addEntry(entry) {
    const val = entry.value;
    switch (entry.type) {
      case 'domain': {
        const cur = new Set(rule.domains || []);
        if (!cur.has(val)) onPatch({ domains: [...(rule.domains || []), val] });
        break;
      }
      case 'suffix': {
        const cur = new Set(rule.domainSuffixes || []);
        if (!cur.has(val)) onPatch({ domainSuffixes: [...(rule.domainSuffixes || []), val] });
        break;
      }
      case 'keyword': {
        const cur = new Set(rule.domainKeywords || []);
        if (!cur.has(val)) onPatch({ domainKeywords: [...(rule.domainKeywords || []), val] });
        break;
      }
      case 'cidr': {
        const cur = new Set(rule.ipCidrs || []);
        if (!cur.has(val)) onPatch({ ipCidrs: [...(rule.ipCidrs || []), val] });
        break;
      }
      default: break;
    }
  }

  const totalPages = Math.ceil(filtered.length / RS_PAGE_SIZE);
  const pageItems = filtered.slice(page * RS_PAGE_SIZE, (page + 1) * RS_PAGE_SIZE);

  const addedValues = useMemo(() => new Set([
    ...(rule.domains || []),
    ...(rule.domainSuffixes || []),
    ...(rule.domainKeywords || []),
    ...(rule.ipCidrs || []),
  ]), [rule]);

  return (
    <div className="modal-backdrop" style={{ zIndex: 1100 }} onClick={onClose}>
      <div
        className="modal lg"
        style={{ maxWidth: 680, maxHeight: '85vh', display: 'flex', flexDirection: 'column' }}
        onClick={(e) => e.stopPropagation()}
      >
        <div className="modal-head">
          <div>
            <h3 style={{ margin: 0 }}>Содержимое: <code style={{ fontSize: 14 }}>{tag}</code></h3>
            <small className="muted">Кликните запись чтобы добавить в правило</small>
          </div>
          <button className="btn btn-ghost sm" onClick={onClose}>Закрыть</button>
        </div>

        {status === 'loading' && (
          <div style={{ padding: 32, textAlign: 'center', color: 'var(--text-muted)' }}>
            Скачивание и декомпиляция…<br />
            <small>Может занять 10–30 секунд</small>
          </div>
        )}
        {status === 'error' && (
          <div style={{ padding: 24 }}>
            <div className="conflict-banner danger"><span>✗</span><div>{error}</div></div>
          </div>
        )}

        {status === 'done' && data && (
          <>
            <div style={{ padding: '8px 20px', borderBottom: '1px solid var(--border)', display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
              <span className="badge info">всего: {data.stats.total.toLocaleString()}</span>
              {data.stats.domain > 0 && <span className="badge">доменов: {data.stats.domain.toLocaleString()}</span>}
              {data.stats.suffix > 0 && <span className="badge">суффиксов: {data.stats.suffix.toLocaleString()}</span>}
              {data.stats.cidr > 0 && <span className="badge">CIDR: {data.stats.cidr.toLocaleString()}</span>}
            </div>
            <div style={{ padding: '8px 20px', borderBottom: '1px solid var(--border)', display: 'flex', gap: 8 }}>
              <input
                ref={inputRef}
                className="input"
                style={{ flex: 1 }}
                placeholder="Поиск: youtube, 149.154, .ru…"
                value={search}
                onChange={(e) => onSearchChange(e.target.value)}
              />
              <select className="select" style={{ width: 130 }} value={typeFilter} onChange={(e) => onTypeChange(e.target.value)}>
                <option value="all">Все типы</option>
                {Object.entries(RS_TYPE_LABELS).map(([k, v]) => (
                  <option key={k} value={k}>{v}</option>
                ))}
              </select>
            </div>
            <div style={{ flex: 1, overflow: 'auto', padding: '0 20px' }}>
              {filtered.length === 0 ? (
                <div className="muted" style={{ padding: '20px 0', textAlign: 'center' }}>Ничего не найдено</div>
              ) : (
                <>
                  <div style={{ fontSize: 12, color: 'var(--text-muted)', padding: '6px 0' }}>
                    {filtered.length.toLocaleString()} / {data.stats.total.toLocaleString()}
                    {totalPages > 1 && ` · стр. ${page + 1}/${totalPages}`}
                    <span className="muted" style={{ marginLeft: 12 }}>— нажмите строку чтобы добавить в правило</span>
                  </div>
                  <table className="table" style={{ fontSize: 12 }}>
                    <thead>
                      <tr><th style={{ width: 70 }}>Тип</th><th>Значение</th><th style={{ width: 30 }}></th></tr>
                    </thead>
                    <tbody>
                      {pageItems.map((e, i) => {
                        const already = addedValues.has(e.value);
                        return (
                          <tr
                            key={i}
                            style={{ cursor: already ? 'default' : 'pointer', opacity: already ? 0.5 : 1 }}
                            onClick={() => !already && addEntry(e)}
                            title={already ? 'Уже добавлено' : `Добавить в ${e.type === 'cidr' ? 'IP/CIDR' : e.type === 'suffix' ? 'суффиксы' : e.type === 'keyword' ? 'ключевые слова' : 'домены'}`}
                          >
                            <td><span className="badge" style={{ fontSize: 10 }}>{RS_TYPE_LABELS[e.type] || e.type}</span></td>
                            <td className="text-mono" style={{ wordBreak: 'break-all', userSelect: 'all' }}>{e.value}</td>
                            <td style={{ color: 'var(--text-muted)', fontSize: 14 }}>{already ? '✓' : '+'}</td>
                          </tr>
                        );
                      })}
                    </tbody>
                  </table>
                  {totalPages > 1 && (
                    <div className="flex" style={{ gap: 8, padding: '10px 0', justifyContent: 'center' }}>
                      <button className="btn btn-ghost sm" disabled={page === 0} onClick={() => setPage(0)}>«</button>
                      <button className="btn btn-ghost sm" disabled={page === 0} onClick={() => setPage((p) => p - 1)}>‹</button>
                      <span className="muted" style={{ lineHeight: '28px', fontSize: 12 }}>{page + 1} / {totalPages}</span>
                      <button className="btn btn-ghost sm" disabled={page >= totalPages - 1} onClick={() => setPage((p) => p + 1)}>›</button>
                      <button className="btn btn-ghost sm" disabled={page >= totalPages - 1} onClick={() => setPage(totalPages - 1)}>»</button>
                    </div>
                  )}
                </>
              )}
            </div>
          </>
        )}
      </div>
    </div>
  );
}

export function RuleEditor({ rule, onUpdate, onClose, onRemove, mode = 'builder', availableRuleSets = [] }) {
  const [view, setView] = useState(mode); // builder | json
  const [jsonDraft, setJsonDraft] = useState(() => JSON.stringify(rule, null, 2));
  const [jsonError, setJsonError] = useState('');
  const [browseTag, setBrowseTag] = useState(null); // { tag, url } | null
  const errors = ruleErrors(rule);

  // Индекс URL по тегу из доступных rule-sets
  const ruleSetUrlMap = useMemo(() => {
    const map = {};
    for (const rs of availableRuleSets) map[rs.tag] = rs.url;
    return map;
  }, [availableRuleSets]);

  function patch(p) {
    onUpdate(rule.id, p);
  }

  function applyJson() {
    try {
      const parsed = JSON.parse(jsonDraft);
      onUpdate(rule.id, { ...parsed, id: rule.id });
      setJsonError('');
    } catch (err) {
      setJsonError(err.message);
    }
  }

  return (
    <div className="drawer-body">
      <div className="tabs">
        <button className={`tab ${view === 'builder' ? 'active' : ''}`} onClick={() => setView('builder')}>Конструктор</button>
        <button className={`tab ${view === 'json' ? 'active' : ''}`} onClick={() => { setJsonDraft(JSON.stringify(rule, null, 2)); setView('json'); }}>Raw JSON</button>
      </div>

      {view === 'builder' ? (
        <>
          <div className="field">
            <span className="field-label">Название</span>
            <input className="input" value={rule.name} onChange={(e) => patch({ name: e.target.value })} />
          </div>

          <div className="field-row">
            <div className="field">
              <span className="field-label">Outbound</span>
              <select className="select" value={rule.outbound} onChange={(e) => patch({ outbound: e.target.value })}>
                <option value="direct">direct (напрямую)</option>
                <option value="vpn">vpn (через выбранный сервер)</option>
                <option value="block">block (заблокировать)</option>
              </select>
            </div>
            <div className="field">
              <span className="field-label">Состояние</span>
              <label className="checkbox">
                <input
                  type="checkbox"
                  checked={rule.enabled !== false}
                  onChange={(e) => patch({ enabled: e.target.checked })}
                />
                Правило включено
              </label>
            </div>
          </div>

          <div className="field">
            <span className="field-label">Rule-sets (geo-базы)</span>
            <ChipsInput
              value={rule.ruleSets || []}
              onChange={(v) => patch({ ruleSets: v })}
              placeholder="geosite-runet"
              validate={validRuleSetTag}
            />
            {/* Кнопки просмотра содержимого для выбранных rule-sets */}
            {(rule.ruleSets || []).length > 0 && (
              <div className="field-hint" style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 4 }}>
                {(rule.ruleSets || []).map((tag) => {
                  const url = ruleSetUrlMap[tag];
                  return url ? (
                    <button
                      key={tag}
                      className="btn btn-ghost sm"
                      style={{ padding: '0 6px', fontSize: 11 }}
                      onClick={() => setBrowseTag({ tag, url })}
                      title={`Просмотреть содержимое ${tag}`}
                    >
                      🔍 {tag}
                    </button>
                  ) : null;
                })}
              </div>
            )}
            {availableRuleSets.length > 0 && (
              <div className="field-hint">
                Доступны:{' '}
                {availableRuleSets.map((rs) => (
                  <span key={rs.tag} style={{ display: 'inline-flex', alignItems: 'center', marginRight: 4 }}>
                    <button
                      className="btn btn-ghost sm"
                      style={{ padding: '0 6px', marginRight: 2 }}
                      onClick={() => {
                        const current = new Set(rule.ruleSets || []);
                        if (!current.has(rs.tag)) {
                          patch({ ruleSets: [...(rule.ruleSets || []), rs.tag] });
                        }
                      }}
                    >
                      + {rs.tag}
                    </button>
                    <button
                      className="btn btn-ghost sm"
                      style={{ padding: '0 4px', fontSize: 12 }}
                      onClick={() => setBrowseTag({ tag: rs.tag, url: rs.url })}
                      title="Просмотреть содержимое"
                    >
                      🔍
                    </button>
                  </span>
                ))}
              </div>
            )}
            {availableRuleSets.length === 0 && (
              <span className="field-hint">
                Настройте rule-sets в Настройках, затем вводите их теги здесь
              </span>
            )}
          </div>

          <div className="field">
            <span className="field-label">Домены (точное совпадение)</span>
            <ChipsInput
              value={rule.domains || []}
              onChange={(v) => patch({ domains: v })}
              placeholder="riotgames.com"
              validate={validDomain}
            />
            {errors.domains.length > 0 && <span className="field-error">Невалидно: {errors.domains.join(', ')}</span>}
          </div>

          <div className="field">
            <span className="field-label">Суффиксы доменов</span>
            <ChipsInput
              value={rule.domainSuffixes || []}
              onChange={(v) => patch({ domainSuffixes: v })}
              placeholder="riotcdn.net"
              validate={validDomain}
            />
            {errors.domainSuffixes.length > 0 && <span className="field-error">Невалидно: {errors.domainSuffixes.join(', ')}</span>}
          </div>

          <div className="field">
            <span className="field-label">IP / CIDR</span>
            <ChipsInput
              value={rule.ipCidrs || []}
              onChange={(v) => patch({ ipCidrs: v })}
              placeholder="104.160.128.0/19"
              validate={isValidCidr}
            />
            {errors.ipCidrs.length > 0 && <span className="field-error">Невалидно: {errors.ipCidrs.join(', ')}</span>}
          </div>

          <div className="field">
            <span className="field-label">Порты (число или диапазон 5000-6000)</span>
            <ChipsInput
              value={rule.ports || []}
              onChange={(v) => patch({ ports: v })}
              placeholder="443"
              validate={(p) => {
                const s = String(p);
                if (s.includes('-')) {
                  const [a, b] = s.split('-');
                  return isValidPort(a) && isValidPort(b);
                }
                return isValidPort(p);
              }}
            />
            {errors.ports.length > 0 && <span className="field-error">Невалидно: {errors.ports.join(', ')}</span>}
          </div>

          <div className="field">
            <span className="field-label">Протоколы</span>
            <div className="flex">
              <label className="checkbox">
                <input
                  type="checkbox"
                  checked={(rule.networks || []).includes('tcp')}
                  onChange={(e) => {
                    const set = new Set(rule.networks || []);
                    e.target.checked ? set.add('tcp') : set.delete('tcp');
                    patch({ networks: Array.from(set) });
                  }}
                />
                TCP
              </label>
              <label className="checkbox">
                <input
                  type="checkbox"
                  checked={(rule.networks || []).includes('udp')}
                  onChange={(e) => {
                    const set = new Set(rule.networks || []);
                    e.target.checked ? set.add('udp') : set.delete('udp');
                    patch({ networks: Array.from(set) });
                  }}
                />
                UDP
              </label>
              <span className="field-hint">Если ничего — оба</span>
            </div>
          </div>
        </>
      ) : (
        <>
          <div className="field">
            <span className="field-label">Сырой JSON правила</span>
            <textarea
              className="textarea"
              style={{ minHeight: 320 }}
              value={jsonDraft}
              onChange={(e) => setJsonDraft(e.target.value)}
            />
            {jsonError && <span className="field-error">{jsonError}</span>}
          </div>
          <div className="btn-group">
            <button className="btn btn-primary" onClick={applyJson}>Применить JSON</button>
            <button className="btn btn-ghost" onClick={() => setJsonDraft(JSON.stringify(rule, null, 2))}>Сбросить</button>
          </div>
        </>
      )}

      {browseTag && (
        <RuleSetBrowseModal
          tag={browseTag.tag}
          url={browseTag.url}
          rule={rule}
          onPatch={(p) => patch(p)}
          onClose={() => setBrowseTag(null)}
        />
      )}
    </div>
  );
}

export function RuleEditorDrawer({ rule, onUpdate, onClose, onRemove, availableRuleSets = [] }) {
  if (!rule) return null;
  const errors = ruleErrors(rule);
  const invalid = hasErrors(errors);

  return (
    <>
      <div className="drawer-backdrop" onClick={onClose} />
      <aside className="drawer">
        <div className="drawer-head">
          <div>
            <h3>Редактирование правила</h3>
            <small className="muted">{rule.name || '(без названия)'}</small>
          </div>
          <button className="btn btn-ghost sm" onClick={onClose}>Закрыть</button>
        </div>
        <RuleEditor rule={rule} onUpdate={onUpdate} onClose={onClose} onRemove={onRemove} availableRuleSets={availableRuleSets} />
        <div className="drawer-foot">
          <button className="btn btn-danger" onClick={() => { if (confirm('Удалить правило?')) { onRemove(rule.id); onClose(); } }}>Удалить</button>
          <div className="btn-group">
            {invalid && <span className="badge danger">Есть ошибки</span>}
            <button className="btn btn-primary" onClick={onClose}>Готово</button>
          </div>
        </div>
      </aside>
    </>
  );
}
