import { useState, useEffect, useRef } from 'react'
import { api } from '../api'

const EMPTY_FORM = { name: '', field: '', pattern: '', output_field: '', function_type: 'extract', flags: '', replace_value: '', retain: false, sequence: 0 }

function PreviewModal({ rows, onClose }) {
  const matched = rows.filter(r => r.extracted_value != null).length
  return (
    <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50" onClick={onClose}>
      <div className="bg-surface rounded-lg shadow-xl w-3/4 max-w-3xl max-h-[80vh] flex flex-col"
        onClick={e => e.stopPropagation()}>
        <div className="flex items-center justify-between px-5 py-3 border-b border-line-soft">
          <span className="text-sm font-medium text-ink-soft">
            Pattern results — <span className="text-muted font-normal">{matched}/{rows.length} matched</span>
          </span>
          <button onClick={onClose} className="text-muted hover:text-ink-soft text-lg leading-none">✕</button>
        </div>
        <div className="overflow-auto flex-1 px-5 py-3">
          <table className="w-full text-xs">
            <thead>
              <tr className="text-left text-muted border-b border-line-soft">
                <th className="pb-2 font-medium w-1/2 pr-4">Raw value</th>
                <th className="pb-2 font-medium">Result</th>
              </tr>
            </thead>
            <tbody>
              {rows.map((r, i) => (
                <tr key={i} className="border-t border-line-soft">
                  <td className="py-1 font-mono text-muted pr-4 break-all">{r.raw_value}</td>
                  <td className={`py-1 font-mono break-all ${r.extracted_value != null ? 'text-ink' : 'text-muted'}`}>
                    {r.extracted_value != null
                      ? (Array.isArray(r.extracted_value) ? r.extracted_value.join(' · ') : String(r.extracted_value))
                      : '—'}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  )
}

function FormPanel({ form, setForm, editing, error, loading, fields, source, onSubmit, onCancel }) {
  const [preview, setPreview] = useState([])
  const [previewing, setPreviewing] = useState(false)
  const [modalOpen, setModalOpen] = useState(false)
  const debounceRef = useRef(null)

  // Auto-preview when field/pattern/flags change, debounced
  useEffect(() => {
    if (!form.field || !form.pattern) { setPreview([]); return }
    clearTimeout(debounceRef.current)
    debounceRef.current = setTimeout(async () => {
      setPreviewing(true)
      try {
        const results = await api.previewRule(source, form.field, form.pattern, form.flags, form.function_type, form.replace_value, 50)
        setPreview(results)
      } catch {
        setPreview([])
      } finally {
        setPreviewing(false)
      }
    }, 500)
    return () => clearTimeout(debounceRef.current)
  }, [form.field, form.pattern, form.flags, form.function_type, form.replace_value, source])

  return (
    <div className="bg-surface border border-line rounded p-4 mb-4">
      <h2 className="text-sm font-semibold text-ink-soft mb-3">{editing ? 'Edit rule' : 'New rule'}</h2>
      <form onSubmit={onSubmit} className="space-y-3">
        <div className="grid grid-cols-2 gap-3">
          <div>
            <label className="text-xs text-muted block mb-1">Rule name</label>
            <input
              className="w-full border border-line rounded px-3 py-1.5 text-sm focus:outline-none focus:border-accent"
              value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))}
              placeholder="e.g. First 20"
            />
          </div>
          <div>
            <label className="text-xs text-muted block mb-1">Sequence</label>
            <input
              type="number"
              className="w-full border border-line rounded px-3 py-1.5 text-sm focus:outline-none focus:border-accent"
              value={form.sequence} onChange={e => setForm(f => ({ ...f, sequence: parseInt(e.target.value) || 0 }))}
            />
          </div>
        </div>
        <div className="grid grid-cols-2 gap-3">
          <div>
            <label className="text-xs text-muted block mb-1">Input field</label>
            {fields.length > 0 ? (
              <select
                className="w-full border border-line rounded px-3 py-1.5 text-sm focus:outline-none focus:border-accent"
                value={form.field} onChange={e => setForm(f => ({ ...f, field: e.target.value }))}
              >
                <option value="">— select field —</option>
                {fields.map(f => <option key={f} value={f}>{f}</option>)}
              </select>
            ) : (
              <input
                className="w-full border border-line rounded px-3 py-1.5 text-sm focus:outline-none focus:border-accent"
                value={form.field} onChange={e => setForm(f => ({ ...f, field: e.target.value }))}
                placeholder="e.g. description"
              />
            )}
          </div>
          <div>
            <label className="text-xs text-muted block mb-1">Output field</label>
            <input
              className="w-full border border-line rounded px-3 py-1.5 text-sm focus:outline-none focus:border-accent"
              value={form.output_field} onChange={e => setForm(f => ({ ...f, output_field: e.target.value }))}
              placeholder="e.g. merchant"
            />
          </div>
        </div>
        <div>
          <label className="text-xs text-muted block mb-1">Pattern (regex)</label>
          <input
            className="w-full border border-line rounded px-3 py-1.5 text-sm font-mono focus:outline-none focus:border-accent"
            value={form.pattern} onChange={e => setForm(f => ({ ...f, pattern: e.target.value }))}
            placeholder="e.g. .{1,20}"
          />
        </div>
        <div className="grid grid-cols-2 gap-3">
          <div>
            <label className="text-xs text-muted block mb-1">Function</label>
            <select
              className="w-full border border-line rounded px-3 py-1.5 text-sm focus:outline-none focus:border-accent"
              value={form.function_type} onChange={e => setForm(f => ({ ...f, function_type: e.target.value }))}
            >
              <option value="extract">extract</option>
              <option value="replace">replace</option>
            </select>
          </div>
          <div>
            <label className="text-xs text-muted block mb-1">Flags</label>
            <input
              className="w-full border border-line rounded px-3 py-1.5 text-sm font-mono focus:outline-none focus:border-accent"
              value={form.flags} onChange={e => setForm(f => ({ ...f, flags: e.target.value }))}
              placeholder="e.g. i"
            />
          </div>
        </div>
        {form.function_type === 'extract' && (
          <label className="flex items-center gap-2 text-xs text-ink-soft cursor-pointer select-none">
            <input
              type="checkbox"
              checked={!!form.retain}
              onChange={e => setForm(f => ({ ...f, retain: e.target.checked }))}
            />
            Retain extracted value in output field even when a mapping is applied
          </label>
        )}
        {form.function_type === 'replace' && (
          <div>
            <label className="text-xs text-muted block mb-1">Replacement string</label>
            <input
              className="w-full border border-line rounded px-3 py-1.5 text-sm font-mono focus:outline-none focus:border-accent"
              value={form.replace_value} onChange={e => setForm(f => ({ ...f, replace_value: e.target.value }))}
              placeholder="e.g. leave blank to delete the match"
            />
          </div>
        )}
        {/* Live preview */}
        {(preview.length > 0 || previewing) && (
          <div className="border border-line-soft rounded p-2 bg-raised">
            <div className="flex items-center justify-between mb-1">
              <p className="text-xs text-muted">
                {previewing ? 'Testing…' : `${preview.filter(r => r.extracted_value != null).length}/${preview.length} matched`}
              </p>
              {!previewing && preview.length > 0 && (
                <button type="button" onClick={() => setModalOpen(true)}
                  className="text-xs text-accent hover:text-accent">expand</button>
              )}
            </div>
            {!previewing && (
              <table className="w-full text-xs">
                <tbody>
                  {preview.slice(0, 5).map((r, i) => (
                    <tr key={i} className="border-t border-line-soft first:border-0">
                      <td className="py-0.5 font-mono text-muted truncate max-w-0 w-1/2 pr-3">{r.raw_value}</td>
                      <td className={`py-0.5 font-mono truncate ${r.extracted_value != null ? 'text-ink' : 'text-muted'}`}>
                        {r.extracted_value != null
                          ? (Array.isArray(r.extracted_value) ? r.extracted_value.join(' · ') : String(r.extracted_value))
                          : '—'}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
          </div>
        )}

        {modalOpen && <PreviewModal rows={preview} onClose={() => setModalOpen(false)} />}

        {error && <p className="text-xs text-danger">{error}</p>}
        <div className="flex gap-2">
          <button type="submit" disabled={loading}
            className="text-sm bg-blue-600 text-white px-3 py-1.5 rounded hover:bg-blue-700 disabled:opacity-50">
            {loading ? 'Saving…' : (editing ? 'Save' : 'Create')}
          </button>
          <button type="button" onClick={onCancel}
            className="text-sm text-muted px-3 py-1.5 rounded hover:bg-raised">
            Cancel
          </button>
        </div>
      </form>
    </div>
  )
}

export default function Rules({ source, onStale }) {
  const [rules, setRules] = useState([])
  const [creating, setCreating] = useState(false)
  const [editing, setEditing] = useState(null)
  const [expanded, setExpanded] = useState(null)
  const [form, setForm] = useState(EMPTY_FORM)
  const [testResults, setTestResults] = useState({})
  const [fields, setFields] = useState([])
  const [error, setError] = useState('')
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    if (!source) return
    api.getRules(source).then(setRules).catch(() => {})
    setTestResults({})
    api.getFields(source).then(f => setFields(f.map(x => x.key))).catch(() => {})
  }, [source])

  function startCreate() {
    setForm(EMPTY_FORM)
    setEditing(null)
    setCreating(true)
    setError('')
  }

  function startEdit(rule) {
    setForm({
      name: rule.name,
      field: rule.field,
      pattern: rule.pattern,
      output_field: rule.output_field,
      function_type: rule.function_type || 'extract',
      flags: rule.flags || '',
      replace_value: rule.replace_value || '',
      retain: rule.retain || false,
      sequence: rule.sequence,
    })
    setEditing(rule.id)
    setCreating(false)
    setError('')
  }

  async function handleSubmit(e, ruleId = null) {
    e.preventDefault()
    setError('')
    setLoading(true)
    const id = ruleId ?? editing
    try {
      if (id) {
        await api.updateRule(id, { ...form, source_name: source })
      } else {
        await api.createRule({ ...form, source_name: source })
      }
      onStale?.(source)
      const updated = await api.getRules(source)
      setRules(updated)
      setCreating(false)
      setEditing(null)
      setExpanded(null)
    } catch (err) {
      setError(err.message)
    } finally {
      setLoading(false)
    }
  }

  async function handleDelete(id) {
    if (!confirm('Delete this rule and all its mappings?')) return
    try {
      await api.deleteRule(id)
      onStale?.(source)
      setRules(r => r.filter(x => x.id !== id))
      setTestResults(t => { const n = { ...t }; delete n[id]; return n })
    } catch (err) {
      alert(err.message)
    }
  }

  async function handleTest(id) {
    try {
      const res = await api.testRule(id)
      setTestResults(t => ({ ...t, [id]: res.results }))
    } catch (err) {
      alert(err.message)
    }
  }

  async function handleToggle(rule) {
    try {
      await api.updateRule(rule.id, { enabled: !rule.enabled })
      onStale?.(source)
      setRules(r => r.map(x => x.id === rule.id ? { ...x, enabled: !x.enabled } : x))
    } catch (err) {
      alert(err.message)
    }
  }

  if (!source) return <div className="p-4 sm:p-6 text-sm text-muted">Select a source first.</div>

  return (
    <div className="p-4 sm:p-6 max-w-3xl">
      <div className="flex items-center justify-between mb-6">
        <h1 className="text-xl font-semibold text-ink">Rules — {source}</h1>
        <button onClick={startCreate}
          className="text-sm bg-blue-600 text-white px-3 py-1.5 rounded hover:bg-blue-700">
          New rule
        </button>
      </div>

      {creating && (
        <FormPanel
          form={form} setForm={setForm} editing={false}
          error={error} loading={loading} fields={fields} source={source}
          onSubmit={handleSubmit}
          onCancel={() => { setCreating(false); setError('') }}
        />
      )}

      {rules.length === 0 && !creating && (
        <p className="text-sm text-muted">No rules yet. Add a regex rule to start extracting values.</p>
      )}

      <div className="space-y-2">
        {rules.map(rule => {
          const isExpanded = expanded === rule.id
          return (
            <div key={rule.id} className="bg-surface border border-line rounded">
              {/* Header — always visible, click to expand/collapse */}
              <div
                className="flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-raised select-none"
                onClick={() => {
                  if (isExpanded) { setExpanded(null); setEditing(null) }
                  else { setExpanded(rule.id); startEdit(rule) }
                }}
              >
                <button
                  onClick={e => { e.stopPropagation(); handleToggle(rule) }}
                  className={`w-8 h-4 rounded-full flex-shrink-0 transition-colors ${rule.enabled ? 'bg-blue-500' : 'bg-raised'}`}
                  title={rule.enabled ? 'Disable' : 'Enable'}
                />
                <div className="flex-1 min-w-0">
                  <span className="font-medium text-ink text-sm">{rule.name}</span>
                  <span className="text-muted text-xs ml-2">seq {rule.sequence}</span>
                  {!isExpanded && (
                    <div className="text-xs text-muted mt-0.5 truncate">
                      <span className="font-mono">{rule.field}</span>
                      <span className="mx-1">→</span>
                      <span className="font-mono bg-raised px-1 rounded">{rule.pattern}</span>
                      {rule.flags && <span className="text-accent ml-1">/{rule.flags}</span>}
                      <span className="mx-1">→</span>
                      <span className="font-mono">{rule.output_field}</span>
                      {rule.function_type === 'replace' && <span className="ml-1 text-warn">(replace)</span>}
                    </div>
                  )}
                </div>
                <span className="text-xs text-muted flex-shrink-0">{isExpanded ? '▲' : '▼'}</span>
              </div>

              {/* Expanded content */}
              {isExpanded && (
                <div className="border-t border-line-soft">
                  <div className="px-4 pt-3 pb-1 flex justify-end">
                    <button onClick={e => { e.stopPropagation(); handleDelete(rule.id) }}
                      className="text-xs text-danger hover:text-danger">Delete</button>
                  </div>
                  <div className="px-4 pb-4">
                    <FormPanel
                      form={form} setForm={setForm} editing={true}
                      error={error} loading={loading} fields={fields} source={source}
                      onSubmit={e => handleSubmit(e, rule.id)}
                      onCancel={() => { setEditing(null); setExpanded(null) }}
                    />
                  </div>
                </div>
              )}
            </div>
          )
        })}
      </div>
    </div>
  )
}
