import { useState, useEffect, useCallback } from 'react'
import {
  Save, RotateCcw, RefreshCw, Plus, Trash2, ChevronDown, ChevronRight,
  Check, X, Eye as EyeIcon, EyeOff, Send, Clock, Zap,
  Calendar, AlertTriangle, Copy, Moon, AlertCircle, Layers,
  Wifi, WifiOff, Mail, Globe, Radio, MessageSquare
} from 'lucide-react'
import ChannelPicker from '@/components/ChannelPicker'
import NodePicker from '@/components/NodePicker'

// Types
interface NotificationRuleConfig {
  name: string
  enabled: boolean
  trigger_type: 'condition' | 'schedule'
  categories: string[]
  min_severity: string
  schedule_frequency: 'daily' | 'twice_daily' | 'weekly'
  schedule_time: string
  schedule_time_2: string
  schedule_days: string[]
  message_type: string
  custom_message: string
  delivery_type: string
  broadcast_channel: number
  node_ids: string[]
  smtp_host: string
  smtp_port: number
  smtp_user: string
  smtp_password: string
  smtp_tls: boolean
  from_address: string
  recipients: string[]
  webhook_url: string
  webhook_headers: Record<string, string>
  cooldown_minutes: number
  override_quiet: boolean
}

interface NotificationsConfig {
  enabled: boolean
  quiet_hours_enabled: boolean
  quiet_hours_start: string
  quiet_hours_end: string
  rules: NotificationRuleConfig[]
}

interface AlertCategory {
  id: string
  name: string
  description: string
  default_severity: string
  example_message: string
}

interface RuleStats {
  last_fired: number | null
  last_test: number | null
  fire_count: number
}

interface SourceHealth {
  [category: string]: {
    enabled: boolean
    active_events: number
    source: string
    status: 'ok' | 'disabled' | 'no_data'
  }
}

interface TestResult {
  live_data_summary?: string[]
  conditions_matched?: number
  preview_messages?: string[]
  is_example?: boolean
  conditions_below_threshold?: number
  below_threshold_summary?: string
  below_threshold_events?: { headline: string; severity: string }[]
  suggestion?: string
  delivered?: boolean
  delivery_method?: string
  delivery_result?: string
  delivery_error?: string
  can_send_live?: boolean
  source_health?: SourceHealth
  rule_stats?: RuleStats
  // Legacy
  success?: boolean
  message?: string
}

interface ChannelTestResult {
  success: boolean
  message: string
  error: string
  details: Record<string, unknown>
}

// Severity levels with descriptions
const SEVERITY_OPTIONS = [
  { value: 'routine', label: 'Routine', description: 'Informational, no time pressure (ducting, new node, weather advisory, battery declining)' },
  { value: 'priority', label: 'Priority', description: 'Needs attention soon (severe weather, fire nearby, node offline, HF blackout)' },
  { value: 'immediate', label: 'Immediate', description: 'Act now, drop everything (fire at infrastructure, extreme weather, region blackout)' },
]

// Notification rule templates
const RULE_TEMPLATES = [
  {
    id: "mesh_health",
    name: "Mesh Health Monitoring",
    description: "Infrastructure problems - offline nodes, low battery, channel congestion",
    rule: {
      name: "Mesh Health Monitoring",
      enabled: true,
      trigger_type: "condition" as const,
      categories: ["infra_offline", "critical_node_down", "infra_recovery", "battery_warning", "battery_critical", "battery_emergency", "high_utilization", "packet_flood", "mesh_score_low"],
      min_severity: "routine",
      delivery_type: "mesh_broadcast",
      broadcast_channel: 0,
      cooldown_minutes: 30,
      override_quiet: false,
      schedule_frequency: "daily" as const,
      schedule_time: "07:00",
      schedule_time_2: "",
      schedule_days: [] as string[],
      message_type: "",
      custom_message: "",
      node_ids: [] as string[],
      smtp_host: "",
      smtp_port: 587,
      smtp_user: "",
      smtp_password: "",
      smtp_tls: true,
      from_address: "",
      recipients: [] as string[],
      webhook_url: "",
      webhook_headers: {} as Record<string, string>,
    }
  },
  {
    id: "weather_fire",
    name: "Weather & Fire Alerts",
    description: "Environmental threats - severe weather, nearby wildfires, new ignitions, flooding",
    rule: {
      name: "Weather & Fire Alerts",
      enabled: true,
      trigger_type: "condition" as const,
      categories: ["weather_warning", "fire_proximity", "new_ignition", "stream_flood_warning"],
      min_severity: "priority",
      delivery_type: "mesh_broadcast",
      broadcast_channel: 0,
      cooldown_minutes: 15,
      override_quiet: false,
      schedule_frequency: "daily" as const,
      schedule_time: "07:00",
      schedule_time_2: "",
      schedule_days: [] as string[],
      message_type: "",
      custom_message: "",
      node_ids: [] as string[],
      smtp_host: "",
      smtp_port: 587,
      smtp_user: "",
      smtp_password: "",
      smtp_tls: true,
      from_address: "",
      recipients: [] as string[],
      webhook_url: "",
      webhook_headers: {} as Record<string, string>,
    }
  },
  {
    id: "rf_conditions",
    name: "RF Conditions",
    description: "Propagation changes - solar events, HF blackouts, tropospheric ducting",
    rule: {
      name: "RF Conditions",
      enabled: true,
      trigger_type: "condition" as const,
      categories: ["hf_blackout", "tropospheric_ducting", "geomagnetic_storm"],
      min_severity: "routine",
      delivery_type: "mesh_broadcast",
      broadcast_channel: 0,
      cooldown_minutes: 60,
      override_quiet: false,
      schedule_frequency: "daily" as const,
      schedule_time: "07:00",
      schedule_time_2: "",
      schedule_days: [] as string[],
      message_type: "",
      custom_message: "",
      node_ids: [] as string[],
      smtp_host: "",
      smtp_port: 587,
      smtp_user: "",
      smtp_password: "",
      smtp_tls: true,
      from_address: "",
      recipients: [] as string[],
      webhook_url: "",
      webhook_headers: {} as Record<string, string>,
    }
  },
  {
    id: "road_traffic",
    name: "Road & Traffic",
    description: "Road closures and severe congestion",
    rule: {
      name: "Road & Traffic",
      enabled: true,
      trigger_type: "condition" as const,
      categories: ["road_closure", "traffic_congestion"],
      min_severity: "routine",
      delivery_type: "mesh_broadcast",
      broadcast_channel: 0,
      cooldown_minutes: 30,
      override_quiet: false,
      schedule_frequency: "daily" as const,
      schedule_time: "07:00",
      schedule_time_2: "",
      schedule_days: [] as string[],
      message_type: "",
      custom_message: "",
      node_ids: [] as string[],
      smtp_host: "",
      smtp_port: 587,
      smtp_user: "",
      smtp_password: "",
      smtp_tls: true,
      from_address: "",
      recipients: [] as string[],
      webhook_url: "",
      webhook_headers: {} as Record<string, string>,
    }
  },
  {
    id: "everything_critical",
    name: "Everything Critical",
    description: "All emergency-level events regardless of type",
    rule: {
      name: "Everything Critical",
      enabled: true,
      trigger_type: "condition" as const,
      categories: [] as string[],
      min_severity: "immediate",
      delivery_type: "mesh_broadcast",
      broadcast_channel: 0,
      cooldown_minutes: 5,
      override_quiet: true,
      schedule_frequency: "daily" as const,
      schedule_time: "07:00",
      schedule_time_2: "",
      schedule_days: [] as string[],
      message_type: "",
      custom_message: "",
      node_ids: [] as string[],
      smtp_host: "",
      smtp_port: 587,
      smtp_user: "",
      smtp_password: "",
      smtp_tls: true,
      from_address: "",
      recipients: [] as string[],
      webhook_url: "",
      webhook_headers: {} as Record<string, string>,
    }
  },
  {
    id: "morning_briefing",
    name: "Morning Briefing",
    description: "Daily health and conditions summary at 7am",
    rule: {
      name: "Morning Briefing",
      enabled: true,
      trigger_type: "schedule" as const,
      categories: [] as string[],
      min_severity: "routine",
      schedule_frequency: "daily" as const,
      schedule_time: "07:00",
      schedule_time_2: "",
      schedule_days: [] as string[],
      message_type: "mesh_health_summary",
      custom_message: "",
      delivery_type: "mesh_broadcast",
      broadcast_channel: 0,
      cooldown_minutes: 0,
      override_quiet: false,
      node_ids: [] as string[],
      smtp_host: "",
      smtp_port: 587,
      smtp_user: "",
      smtp_password: "",
      smtp_tls: true,
      from_address: "",
      recipients: [] as string[],
      webhook_url: "",
      webhook_headers: {} as Record<string, string>,
    }
  },
]

// Helper to format relative time
function formatRelativeTime(timestamp: number | null): string {
  if (!timestamp) return 'Never'
  const now = Date.now() / 1000
  const diff = now - timestamp
  if (diff < 60) return 'Just now'
  if (diff < 3600) return `${Math.floor(diff / 60)}m ago`
  if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`
  if (diff < 604800) return `${Math.floor(diff / 86400)}d ago`
  return new Date(timestamp * 1000).toLocaleDateString()
}

// InfoButton component
function InfoButton({ info }: { info: string }) {
  const [open, setOpen] = useState(false)

  return (
    <div className="relative inline-block">
      <button
        type="button"
        onClick={(e) => { e.stopPropagation(); setOpen(!open) }}
        className="ml-1.5 w-4 h-4 rounded-full bg-slate-700 hover:bg-slate-600 text-slate-400 hover:text-slate-200 inline-flex items-center justify-center text-xs transition-colors"
        title="More info"
      >
        ?
      </button>
      {open && (
        <>
          <div className="fixed inset-0 z-40" onClick={() => setOpen(false)} />
          <div className="absolute left-0 top-6 z-50 w-72 p-3 bg-[#1a2332] border border-[#2a3a4a] rounded-lg shadow-xl text-xs text-slate-300 leading-relaxed">
            {info}
          </div>
        </>
      )}
    </div>
  )
}

// Form components
function TextInput({ label, value, onChange, type = 'text', placeholder = '', helper = '', info = '' }: {
  label: string
  value: string
  onChange: (v: string) => void
  type?: string
  placeholder?: string
  helper?: string
  info?: string
}) {
  const [showPassword, setShowPassword] = useState(false)
  const isPassword = type === 'password'

  return (
    <div className="space-y-1">
      <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
        {label}
        {info && <InfoButton info={info} />}
      </label>
      <div className="relative">
        <input
          type={isPassword && !showPassword ? 'password' : 'text'}
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder={placeholder}
          className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 font-mono focus:outline-none focus:border-accent placeholder-slate-600"
        />
        {isPassword && (
          <button
            type="button"
            onClick={() => setShowPassword(!showPassword)}
            className="absolute right-2 top-1/2 -translate-y-1/2 text-slate-500 hover:text-slate-300"
          >
            {showPassword ? <EyeOff size={16} /> : <EyeIcon size={16} />}
          </button>
        )}
      </div>
      {helper && <p className="text-xs text-slate-600">{helper}</p>}
    </div>
  )
}

function NumberInput({ label, value, onChange, min, max, step = 1, helper = '', info = '' }: {
  label: string
  value: number
  onChange: (v: number) => void
  min?: number
  max?: number
  step?: number
  helper?: string
  info?: string
}) {
  return (
    <div className="space-y-1">
      <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
        {label}
        {info && <InfoButton info={info} />}
      </label>
      <input
        type="number"
        value={value}
        onChange={(e) => onChange(Number(e.target.value))}
        min={min}
        max={max}
        step={step}
        className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 font-mono focus:outline-none focus:border-accent"
      />
      {helper && <p className="text-xs text-slate-600">{helper}</p>}
    </div>
  )
}

function Toggle({ label, checked, onChange, helper = '', info = '' }: {
  label: string
  checked: boolean
  onChange: (v: boolean) => void
  helper?: string
  info?: string
}) {
  return (
    <div className="flex items-center justify-between py-2">
      <div>
        <span className="flex items-center text-sm text-slate-300">
          {label}
          {info && <InfoButton info={info} />}
        </span>
        {helper && <p className="text-xs text-slate-600">{helper}</p>}
      </div>
      <button
        type="button"
        onClick={() => onChange(!checked)}
        className={`relative w-11 h-6 rounded-full transition-colors ${
          checked ? 'bg-accent' : 'bg-[#1e2a3a]'
        }`}
      >
        <span
          className={`absolute top-1 left-1 w-4 h-4 rounded-full bg-white transition-transform ${
            checked ? 'translate-x-5' : ''
          }`}
        />
      </button>
    </div>
  )
}

function TimeInput({ label, value, onChange, helper = '', info = '' }: {
  label: string
  value: string
  onChange: (v: string) => void
  helper?: string
  info?: string
}) {
  return (
    <div className="space-y-1">
      <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
        {label}
        {info && <InfoButton info={info} />}
      </label>
      <input
        type="time"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 focus:outline-none focus:border-accent"
      />
      {helper && <p className="text-xs text-slate-600">{helper}</p>}
    </div>
  )
}

function ListInput({ label, value, onChange, placeholder = 'Add item...', helper = '', info = '' }: {
  label: string
  value: string[]
  onChange: (v: string[]) => void
  placeholder?: string
  helper?: string
  info?: string
}) {
  const [inputValue, setInputValue] = useState('')

  const addItem = () => {
    if (inputValue.trim() && !value.includes(inputValue.trim())) {
      onChange([...value, inputValue.trim()])
      setInputValue('')
    }
  }

  const removeItem = (index: number) => {
    onChange(value.filter((_, i) => i !== index))
  }

  return (
    <div className="space-y-1">
      <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
        {label}
        {info && <InfoButton info={info} />}
      </label>
      <div className="flex gap-2">
        <input
          type="text"
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), addItem())}
          className="flex-1 px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 font-mono focus:outline-none focus:border-accent"
          placeholder={placeholder}
        />
        <button
          type="button"
          onClick={addItem}
          className="px-3 py-2 bg-accent hover:bg-accent/80 rounded text-sm text-white transition-colors"
        >
          <Plus size={16} />
        </button>
      </div>
      {value.length > 0 && (
        <div className="flex flex-wrap gap-2 mt-2">
          {value.map((item, i) => (
            <span
              key={i}
              className="inline-flex items-center gap-1 px-2 py-1 bg-[#1e2a3a] rounded text-sm text-slate-300"
            >
              {item}
              <button
                type="button"
                onClick={() => removeItem(i)}
                className="text-slate-500 hover:text-red-400"
              >
                <X size={14} />
              </button>
            </span>
          ))}
        </div>
      )}
      {helper && <p className="text-xs text-slate-600">{helper}</p>}
    </div>
  )
}

// Severity selector with descriptions
function SeveritySelector({ value, onChange }: {
  value: string
  onChange: (v: string) => void
}) {
  const [isOpen, setIsOpen] = useState(false)
  const selected = SEVERITY_OPTIONS.find(s => s.value === value) || SEVERITY_OPTIONS[0]

  return (
    <div className="space-y-1">
      <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
        Severity Threshold
        <InfoButton info="Only alerts at or above this severity trigger this rule. ROUTINE = informational, PRIORITY = needs attention, IMMEDIATE = act now." />
      </label>
      <div className="relative">
        <button
          type="button"
          onClick={() => setIsOpen(!isOpen)}
          className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-left flex items-center justify-between hover:border-accent transition-colors"
        >
          <div>
            <span className="text-slate-200">{selected.label}</span>
            <span className="text-slate-500 ml-2">- {selected.description}</span>
          </div>
          <ChevronDown size={16} className={`text-slate-500 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
        </button>
        {isOpen && (
          <>
            <div className="fixed inset-0 z-40" onClick={() => setIsOpen(false)} />
            <div className="absolute left-0 right-0 top-full mt-1 z-50 bg-[#0a0e17] border border-[#1e2a3a] rounded-lg shadow-xl overflow-hidden">
              {SEVERITY_OPTIONS.map((opt) => (
                <button
                  key={opt.value}
                  type="button"
                  onClick={() => { onChange(opt.value); setIsOpen(false) }}
                  className={`w-full px-3 py-2.5 text-left text-sm hover:bg-[#1e2a3a] transition-colors ${
                    value === opt.value ? 'bg-accent/10' : ''
                  }`}
                >
                  <div className="font-medium text-slate-200">{opt.label}</div>
                  <div className="text-xs text-slate-500">{opt.description}</div>
                </button>
              ))}
            </div>
          </>
        )}
      </div>
      <p className="text-xs text-slate-600">Lower = more notifications. "Warning" recommended for most rules.</p>
    </div>
  )
}

// Channel Test Button Component
function ChannelTestButton({ rule }: {
  rule: NotificationRuleConfig
}) {
  const [testing, setTesting] = useState(false)
  const [result, setResult] = useState<ChannelTestResult | null>(null)

  const handleTest = async () => {
    setTesting(true)
    setResult(null)

    try {
      // Build channel config from rule
      let channelConfig: Record<string, unknown> = { type: rule.delivery_type }

      if (rule.delivery_type === 'mesh_broadcast') {
        channelConfig.channel_index = rule.broadcast_channel
      } else if (rule.delivery_type === 'mesh_dm') {
        channelConfig.node_ids = rule.node_ids
      } else if (rule.delivery_type === 'email') {
        channelConfig = {
          type: 'email',
          smtp_host: rule.smtp_host,
          smtp_port: rule.smtp_port,
          smtp_user: rule.smtp_user,
          smtp_password: rule.smtp_password,
          smtp_tls: rule.smtp_tls,
          from_address: rule.from_address,
          recipients: rule.recipients,
        }
      } else if (rule.delivery_type === 'webhook') {
        channelConfig = {
          type: 'webhook',
          url: rule.webhook_url,
          headers: rule.webhook_headers,
        }
      }

      const res = await fetch('/api/notifications/channels/test', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(channelConfig),
      })
      const data = await res.json()
      setResult(data)
    } catch (err) {
      setResult({
        success: false,
        message: 'Test failed',
        error: err instanceof Error ? err.message : 'Unknown error',
        details: {}
      })
    } finally {
      setTesting(false)
    }
  }

  if (!rule.delivery_type) return null

  const icon = {
    mesh_broadcast: <Radio size={14} />,
    mesh_dm: <MessageSquare size={14} />,
    email: <Mail size={14} />,
    webhook: <Globe size={14} />,
  }[rule.delivery_type] || <Wifi size={14} />

  return (
    <div className="space-y-2">
      <button
        type="button"
        onClick={handleTest}
        disabled={testing}
        className="flex items-center gap-2 px-3 py-1.5 bg-slate-700 hover:bg-slate-600 rounded text-sm disabled:opacity-50"
      >
        {testing ? (
          <>
            <RefreshCw size={14} className="animate-spin" />
            Testing...
          </>
        ) : (
          <>
            {icon}
            Test Channel
          </>
        )}
      </button>

      {result && (
        <div className={`p-2 rounded text-xs ${
          result.success
            ? 'bg-green-500/10 border border-green-500/30 text-green-400'
            : 'bg-red-500/10 border border-red-500/30 text-red-400'
        }`}>
          <div className="flex items-start gap-2">
            {result.success ? <Check size={14} className="mt-0.5 flex-shrink-0" /> : <X size={14} className="mt-0.5 flex-shrink-0" />}
            <div>
              <div className="font-medium">{result.message}</div>
              {result.error && <div className="mt-1 text-red-300">{result.error}</div>}
            </div>
          </div>
        </div>
      )}
    </div>
  )
}

// Notification Rule Card Component
function NotificationRuleCard({
  rule,
  ruleIndex,
  categories,
  quietHoursEnabled,
  onChange,
  onDelete,
  onDuplicate,
  onTest,
}: {
  rule: NotificationRuleConfig
  ruleIndex: number
  categories: AlertCategory[]
  quietHoursEnabled: boolean
  onChange: (r: NotificationRuleConfig) => void
  onDelete: () => void
  onDuplicate: () => void
  onTest: () => void
}) {
  const [expanded, setExpanded] = useState(!rule.name)
  const [testing, setTesting] = useState(false)
  const [ruleStats, setRuleStats] = useState<RuleStats | null>(null)
  const [sourceHealth, setSourceHealth] = useState<SourceHealth | null>(null)

  // Fetch rule stats on mount
  useEffect(() => {
    if (rule.name && ruleIndex >= 0) {
      fetch(`/api/notifications/rules/${ruleIndex}/stats`)
        .then(res => res.json())
        .then(data => setRuleStats(data))
        .catch(() => {})

      if (rule.categories?.length) {
        fetch('/api/notifications/rules/sources', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ categories: rule.categories })
        })
          .then(res => res.json())
          .then(data => setSourceHealth(data))
          .catch(() => {})
      }
    }
  }, [rule.name, ruleIndex, rule.categories])

  const deliveryOptions = [
    { value: '', label: '(None)', description: 'Rule matches but does not deliver' },
    { value: 'mesh_broadcast', label: 'Mesh Broadcast', description: 'Send to a mesh radio channel' },
    { value: 'mesh_dm', label: 'Mesh DM', description: 'Direct message to specific nodes' },
    { value: 'email', label: 'Email', description: 'Send via SMTP' },
    { value: 'webhook', label: 'Webhook', description: 'POST to any URL' },
  ]

  const frequencyOptions = [
    { value: 'daily', label: 'Daily' },
    { value: 'twice_daily', label: 'Twice Daily' },
    { value: 'weekly', label: 'Weekly' },
  ]

  const messageTypeOptions = [
    { value: 'mesh_health_summary', label: 'Mesh Health Summary', description: 'Current health score, pillar breakdown, problem nodes' },
    { value: 'rf_propagation_report', label: 'RF Propagation Report', description: 'Solar indices, Kp, ducting conditions' },
    { value: 'alerts_digest', label: 'Active Alerts Digest', description: 'Summary of all active environmental alerts' },
    { value: 'environmental_conditions', label: 'Environmental Conditions', description: 'Full conditions: weather, fire, streams, roads' },
    { value: 'custom', label: 'Custom Message', description: 'Write your own with template tokens' },
  ]

  const dayOptions = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']

  const toggleCategory = (catId: string) => {
    const current = rule.categories || []
    if (current.includes(catId)) {
      onChange({ ...rule, categories: current.filter(c => c !== catId) })
    } else {
      onChange({ ...rule, categories: [...current, catId] })
    }
  }

  const toggleDay = (day: string) => {
    const current = rule.schedule_days || []
    if (current.includes(day)) {
      onChange({ ...rule, schedule_days: current.filter(d => d !== day) })
    } else {
      onChange({ ...rule, schedule_days: [...current, day] })
    }
  }

  const handleTest = async () => {
    setTesting(true)
    await onTest()
    setTesting(false)
  }

  // Get example message for display
  const getExampleMessage = (): string => {
    if (rule.trigger_type === 'schedule') {
      return '[Scheduled report preview would appear here]'
    }
    const ruleCats = rule.categories || []
    if (ruleCats.length === 0 && categories.length > 0) {
      return categories[0].example_message || 'Alert notification'
    }
    const firstCat = categories.find(c => ruleCats.includes(c.id))
    return firstCat?.example_message || 'Alert notification'
  }

  // Generate summary for collapsed view
  const getSummary = () => {
    const parts: string[] = []

    if (rule.trigger_type === 'schedule') {
      const freq = frequencyOptions.find(f => f.value === rule.schedule_frequency)?.label || rule.schedule_frequency
      const msgType = messageTypeOptions.find(m => m.value === rule.message_type)?.label || rule.message_type
      parts.push(`${freq} at ${rule.schedule_time || '??:??'}`)
      parts.push(msgType)
    } else {
      const catCount = rule.categories?.length || 0
      const catText = catCount === 0 ? 'All' : categories.filter(c => rule.categories?.includes(c.id)).map(c => c.name).slice(0, 2).join(', ') + (catCount > 2 ? ` +${catCount - 2}` : '')
      const severity = SEVERITY_OPTIONS.find(s => s.value === rule.min_severity)?.label || rule.min_severity
      parts.push(`${catText} at ${severity}+`)
    }

    // Delivery summary
    if (!rule.delivery_type) {
      parts.push('No delivery')
    } else {
      const delivery = deliveryOptions.find(d => d.value === rule.delivery_type)?.label || rule.delivery_type
      let target = ''
      if (rule.delivery_type === 'mesh_broadcast') {
        target = `Ch ${rule.broadcast_channel}`
      } else if (rule.delivery_type === 'mesh_dm') {
        target = `${rule.node_ids?.length || 0} nodes`
      } else if (rule.delivery_type === 'email') {
        target = rule.recipients?.length ? rule.recipients[0] + (rule.recipients.length > 1 ? ` +${rule.recipients.length - 1}` : '') : 'no recipients'
      } else if (rule.delivery_type === 'webhook') {
        try {
          const url = new URL(rule.webhook_url)
          target = url.hostname
        } catch {
          target = rule.webhook_url?.slice(0, 20) || 'no URL'
        }
      }
      parts.push(`${delivery}${target ? ` (${target})` : ''}`)
    }

    return parts.join(' -> ')
  }

  // Get source status indicators
  const getSourceIndicators = () => {
    if (!sourceHealth || !rule.categories?.length) return null

    const sources = new Map<string, { enabled: boolean; events: number }>()
    for (const [, health] of Object.entries(sourceHealth)) {
      const existing = sources.get(health.source)
      if (existing) {
        existing.events += health.active_events
        existing.enabled = existing.enabled && health.enabled
      } else {
        sources.set(health.source, { enabled: health.enabled, events: health.active_events })
      }
    }

    return Array.from(sources.entries()).map(([source, { enabled, events }]) => (
      <span
        key={source}
        className={`inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs ${
          enabled
            ? 'bg-green-500/10 text-green-400'
            : 'bg-red-500/10 text-red-400'
        }`}
        title={enabled ? `${events} active` : 'Not enabled'}
      >
        {enabled ? <Wifi size={10} /> : <WifiOff size={10} />}
        {source.toUpperCase()}
        {enabled && events > 0 && ` (${events})`}
      </span>
    ))
  }

  return (
    <div className={`border rounded-lg overflow-hidden ${rule.enabled ? 'border-[#1e2a3a]' : 'border-slate-700 opacity-60'}`}>
      {/* Header */}
      <div
        className="flex items-center justify-between p-3 bg-[#0a0e17] cursor-pointer"
        onClick={() => setExpanded(!expanded)}
      >
        <div className="flex items-center gap-3 min-w-0 flex-1">
          {expanded ? <ChevronDown size={16} className="text-slate-500 flex-shrink-0" /> : <ChevronRight size={16} className="text-slate-500 flex-shrink-0" />}
          <button
            onClick={(e) => { e.stopPropagation(); onChange({ ...rule, enabled: !rule.enabled }) }}
            className={`w-2 h-2 rounded-full flex-shrink-0 ${rule.enabled ? 'bg-green-500' : 'bg-slate-500'}`}
            title={rule.enabled ? 'Enabled' : 'Disabled'}
          />
          {rule.trigger_type === 'schedule' ? (
            <Clock size={14} className="text-blue-400 flex-shrink-0" />
          ) : (
            <Zap size={14} className="text-yellow-400 flex-shrink-0" />
          )}
          <span className="font-medium text-slate-200 truncate">{rule.name || 'New Rule'}</span>
          {!expanded && (
            <span className={`text-xs truncate hidden sm:block ${!rule.delivery_type ? 'text-amber-400' : 'text-slate-500'}`}>
              {getSummary()}
            </span>
          )}
        </div>
        <div className="flex items-center gap-1 flex-shrink-0">
          {/* Stats badge */}
          {ruleStats && !expanded && (
            <span className="hidden sm:inline-flex items-center gap-1 px-2 py-0.5 bg-slate-800 rounded text-xs text-slate-400 mr-2">
              {ruleStats.last_fired ? formatRelativeTime(ruleStats.last_fired) : 'Never fired'}
            </span>
          )}
          {/* Source indicators */}
          {!expanded && (
            <div className="hidden md:flex items-center gap-1 mr-2">
              {getSourceIndicators()}
            </div>
          )}
          <button
            onClick={(e) => { e.stopPropagation(); handleTest() }}
            disabled={testing || !rule.name}
            className="p-1.5 text-blue-400 hover:text-blue-300 hover:bg-blue-500/10 rounded disabled:opacity-50"
            title="Test rule"
          >
            <Send size={14} />
          </button>
          <button
            onClick={(e) => { e.stopPropagation(); onDuplicate() }}
            className="p-1.5 text-slate-400 hover:text-slate-200 hover:bg-slate-500/10 rounded"
            title="Duplicate"
          >
            <Copy size={14} />
          </button>
          <button
            onClick={(e) => { e.stopPropagation(); onDelete() }}
            className="p-1.5 text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded"
            title="Delete"
          >
            <Trash2 size={14} />
          </button>
        </div>
      </div>

      {/* Status line (collapsed view) */}
      {!expanded && rule.name && (
        <div className="px-3 pb-2 pt-0 bg-[#0a0e17] flex items-center gap-2 flex-wrap text-xs">
          {!rule.delivery_type && (
            <span className="inline-flex items-center gap-1 px-1.5 py-0.5 bg-amber-500/10 text-amber-400 rounded">
              <AlertCircle size={10} />
              No delivery method
            </span>
          )}
          {ruleStats?.fire_count !== undefined && ruleStats.fire_count > 0 && (
            <span className="text-slate-500">
              Fired {ruleStats.fire_count}x
            </span>
          )}
        </div>
      )}

      {/* Expanded content */}
      {expanded && (
        <div className="p-4 space-y-6 border-t border-[#1e2a3a]">
          {/* Rule name */}
          <TextInput
            label="Rule Name"
            value={rule.name}
            onChange={(v) => onChange({ ...rule, name: v })}
            placeholder="e.g., Emergency Broadcast, Daily Health Report"
            helper="A descriptive name for this rule"
          />

          {/* Trigger type toggle */}
          <div className="space-y-2">
            <label className="text-xs text-slate-500 uppercase tracking-wide">Trigger Type</label>
            <div className="flex gap-2">
              <button
                type="button"
                onClick={() => onChange({ ...rule, trigger_type: 'condition' })}
                className={`flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-lg border transition-colors ${
                  rule.trigger_type !== 'schedule'
                    ? 'bg-accent/10 border-accent text-accent'
                    : 'bg-[#0a0e17] border-[#1e2a3a] text-slate-400 hover:text-slate-200'
                }`}
              >
                <Zap size={16} />
                <span>Condition</span>
              </button>
              <button
                type="button"
                onClick={() => onChange({ ...rule, trigger_type: 'schedule' })}
                className={`flex-1 flex items-center justify-center gap-2 px-4 py-3 rounded-lg border transition-colors ${
                  rule.trigger_type === 'schedule'
                    ? 'bg-accent/10 border-accent text-accent'
                    : 'bg-[#0a0e17] border-[#1e2a3a] text-slate-400 hover:text-slate-200'
                }`}
              >
                <Clock size={16} />
                <span>Schedule</span>
              </button>
            </div>
            <p className="text-xs text-slate-600">
              {rule.trigger_type === 'schedule'
                ? 'Send reports on a schedule (daily briefings, weekly digests)'
                : 'React to alert conditions (fires, outages, weather warnings)'}
            </p>
          </div>

          {/* WHEN section - Condition trigger */}
          {rule.trigger_type !== 'schedule' && (
            <div className="space-y-4 p-4 bg-[#0a0e17] rounded-lg border border-[#1e2a3a]">
              <div className="flex items-center gap-2 text-sm font-medium text-slate-300">
                <AlertTriangle size={14} />
                WHEN (Condition)
              </div>

              <SeveritySelector
                value={rule.min_severity}
                onChange={(v) => onChange({ ...rule, min_severity: v })}
              />

              <div className="space-y-2">
                <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
                  Alert Categories
                  <InfoButton info="Select which types of alerts trigger this rule. Leave all unchecked to match ALL categories." />
                </label>
                <div className="text-xs text-slate-500 mb-2">
                  {(rule.categories?.length || 0) === 0 ? 'All categories (none selected)' : `${rule.categories?.length} selected`}
                </div>
                <div className="max-h-48 overflow-y-auto border border-[#1e2a3a] rounded-lg p-2 space-y-1">
                  {categories.map((cat) => (
                    <label
                      key={cat.id}
                      onClick={() => toggleCategory(cat.id)}
                      className="flex items-start gap-2 p-2 rounded hover:bg-[#1e2a3a]/50 cursor-pointer"
                    >
                      <div className={`w-4 h-4 mt-0.5 rounded border flex items-center justify-center flex-shrink-0 ${
                        rule.categories?.includes(cat.id) ? 'bg-accent border-accent' : 'border-slate-600'
                      }`}>
                        {rule.categories?.includes(cat.id) && <Check size={12} className="text-white" />}
                      </div>
                      <div className="flex-1 min-w-0">
                        <div className="text-sm text-slate-200">{cat.name}</div>
                        <div className="text-xs text-slate-500">{cat.description}</div>
                      </div>
                    </label>
                  ))}
                </div>
              </div>

              {/* Source health display */}
              {sourceHealth && Object.keys(sourceHealth).length > 0 && (
                <div className="space-y-2">
                  <label className="text-xs text-slate-500 uppercase tracking-wide">Data Sources</label>
                  <div className="flex flex-wrap gap-2">
                    {getSourceIndicators()}
                  </div>
                </div>
              )}
            </div>
          )}

          {/* WHEN section - Schedule trigger */}
          {rule.trigger_type === 'schedule' && (
            <div className="space-y-4 p-4 bg-[#0a0e17] rounded-lg border border-[#1e2a3a]">
              <div className="flex items-center gap-2 text-sm font-medium text-slate-300">
                <Calendar size={14} />
                WHEN (Schedule)
              </div>

              <div className="space-y-1">
                <label className="text-xs text-slate-500 uppercase tracking-wide">Frequency</label>
                <select
                  value={rule.schedule_frequency || 'daily'}
                  onChange={(e) => onChange({ ...rule, schedule_frequency: e.target.value as 'daily' | 'twice_daily' | 'weekly' })}
                  className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 focus:outline-none focus:border-accent"
                >
                  {frequencyOptions.map(opt => (
                    <option key={opt.value} value={opt.value}>{opt.label}</option>
                  ))}
                </select>
              </div>

              <div className="grid grid-cols-2 gap-4">
                <TimeInput
                  label="Time"
                  value={rule.schedule_time || '07:00'}
                  onChange={(v) => onChange({ ...rule, schedule_time: v })}
                />
                {rule.schedule_frequency === 'twice_daily' && (
                  <TimeInput
                    label="Second Time"
                    value={rule.schedule_time_2 || '19:00'}
                    onChange={(v) => onChange({ ...rule, schedule_time_2: v })}
                  />
                )}
              </div>

              {rule.schedule_frequency === 'weekly' && (
                <div className="space-y-2">
                  <label className="text-xs text-slate-500 uppercase tracking-wide">Days</label>
                  <div className="flex flex-wrap gap-2">
                    {dayOptions.map((day) => (
                      <button
                        key={day}
                        type="button"
                        onClick={() => toggleDay(day)}
                        className={`px-3 py-1.5 rounded text-sm capitalize transition-colors ${
                          rule.schedule_days?.includes(day)
                            ? 'bg-accent text-white'
                            : 'bg-[#1e2a3a] text-slate-400 hover:text-slate-200'
                        }`}
                      >
                        {day.slice(0, 3)}
                      </button>
                    ))}
                  </div>
                </div>
              )}

              <div className="space-y-1">
                <label className="text-xs text-slate-500 uppercase tracking-wide">Report Type</label>
                <select
                  value={rule.message_type || 'mesh_health_summary'}
                  onChange={(e) => onChange({ ...rule, message_type: e.target.value })}
                  className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 focus:outline-none focus:border-accent"
                >
                  {messageTypeOptions.map(opt => (
                    <option key={opt.value} value={opt.value}>{opt.label}</option>
                  ))}
                </select>
                <p className="text-xs text-slate-600">
                  {messageTypeOptions.find(m => m.value === rule.message_type)?.description}
                </p>
              </div>

              {rule.message_type === 'custom' && (
                <div className="space-y-1">
                  <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
                    Custom Message
                    <InfoButton info="Available tokens: {MESH_SCORE}, {NODE_COUNT}, {NODES_ONLINE}, {ACTIVE_ALERTS}, {KP}, {SFI}, {DATE}, {TIME}" />
                  </label>
                  <textarea
                    value={rule.custom_message || ''}
                    onChange={(e) => onChange({ ...rule, custom_message: e.target.value })}
                    rows={4}
                    placeholder="Good morning! Mesh health: {MESH_SCORE}/100 with {NODE_COUNT} nodes online."
                    className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 font-mono focus:outline-none focus:border-accent placeholder-slate-600"
                  />
                </div>
              )}
            </div>
          )}

          {/* SEND VIA section */}
          <div className="space-y-4 p-4 bg-[#0a0e17] rounded-lg border border-[#1e2a3a]">
            <div className="flex items-center gap-2 text-sm font-medium text-slate-300">
              <Send size={14} />
              SEND VIA
            </div>

            <div className="space-y-1">
              <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
                Delivery Method
                <InfoButton info="Where this notification gets delivered. Select (None) to save the rule without delivery - it will match conditions but won't send until you configure a delivery method." />
              </label>
              <select
                value={rule.delivery_type || ''}
                onChange={(e) => onChange({ ...rule, delivery_type: e.target.value })}
                className="w-full px-3 py-2 bg-[#0a0e17] border border-[#1e2a3a] rounded text-sm text-slate-200 focus:outline-none focus:border-accent"
              >
                {deliveryOptions.map(opt => (
                  <option key={opt.value} value={opt.value}>{opt.label}</option>
                ))}
              </select>
              <p className="text-xs text-slate-600">
                {deliveryOptions.find(d => d.value === (rule.delivery_type || ''))?.description}
              </p>
            </div>

            {/* No delivery warning */}
            {!rule.delivery_type && (
              <div className="flex items-start gap-2 p-3 bg-amber-500/10 border border-amber-500/20 rounded-lg">
                <AlertCircle size={16} className="text-amber-400 mt-0.5 flex-shrink-0" />
                <div className="text-sm text-amber-300">
                  Rule will log matches but not deliver until a delivery method is configured.
                </div>
              </div>
            )}

            {/* Mesh Broadcast fields */}
            {rule.delivery_type === 'mesh_broadcast' && (
              <>
                <ChannelPicker
                  label="Broadcast Channel"
                  value={rule.broadcast_channel ?? 0}
                  onChange={(v) => onChange({ ...rule, broadcast_channel: v })}
                  helper="Select the mesh radio channel"
                  mode="single"
                />
                <ChannelTestButton rule={rule} />
              </>
            )}

            {/* Mesh DM fields */}
            {rule.delivery_type === 'mesh_dm' && (
              <>
                <NodePicker
                  label="Recipient Nodes"
                  value={rule.node_ids || []}
                  onChange={(v) => onChange({ ...rule, node_ids: v })}
                  helper="Nodes that receive direct messages"
                  valueType="node_id_hex"
                />
                <ChannelTestButton rule={rule} />
              </>
            )}

            {/* Email fields */}
            {rule.delivery_type === 'email' && (
              <div className="space-y-4">
                <ListInput
                  label="Recipients"
                  value={rule.recipients || []}
                  onChange={(v) => onChange({ ...rule, recipients: v })}
                  placeholder="email@example.com"
                  helper="Email addresses to receive alerts"
                />

                <details className="group">
                  <summary className="flex items-center gap-2 cursor-pointer text-sm text-slate-400 hover:text-slate-200">
                    <ChevronRight size={14} className="group-open:rotate-90 transition-transform" />
                    SMTP Configuration
                  </summary>
                  <div className="mt-4 space-y-4 pl-6 border-l border-[#1e2a3a]">
                    <div className="grid grid-cols-2 gap-4">
                      <TextInput
                        label="SMTP Host"
                        value={rule.smtp_host || ''}
                        onChange={(v) => onChange({ ...rule, smtp_host: v })}
                        placeholder="smtp.gmail.com"
                      />
                      <NumberInput
                        label="SMTP Port"
                        value={rule.smtp_port ?? 587}
                        onChange={(v) => onChange({ ...rule, smtp_port: v })}
                        min={1}
                        max={65535}
                      />
                    </div>
                    <div className="grid grid-cols-2 gap-4">
                      <TextInput
                        label="Username"
                        value={rule.smtp_user || ''}
                        onChange={(v) => onChange({ ...rule, smtp_user: v })}
                      />
                      <TextInput
                        label="Password"
                        value={rule.smtp_password || ''}
                        onChange={(v) => onChange({ ...rule, smtp_password: v })}
                        type="password"
                        info="Gmail users: use an App Password from myaccount.google.com/apppasswords"
                      />
                    </div>
                    <Toggle
                      label="Use TLS"
                      checked={rule.smtp_tls ?? true}
                      onChange={(v) => onChange({ ...rule, smtp_tls: v })}
                    />
                    <TextInput
                      label="From Address"
                      value={rule.from_address || ''}
                      onChange={(v) => onChange({ ...rule, from_address: v })}
                      placeholder="alerts@yourdomain.com"
                    />
                  </div>
                </details>

                <ChannelTestButton rule={rule} />
              </div>
            )}

            {/* Webhook fields */}
            {rule.delivery_type === 'webhook' && (
              <>
                <TextInput
                  label="Webhook URL"
                  value={rule.webhook_url || ''}
                  onChange={(v) => onChange({ ...rule, webhook_url: v })}
                  placeholder="https://discord.com/api/webhooks/..."
                  helper="POST alert as JSON"
                  info="Works with Discord webhooks, ntfy.sh, Slack, Home Assistant, Pushover, or any HTTP POST endpoint."
                />
                <ChannelTestButton rule={rule} />
              </>
            )}
          </div>

          {/* Behavior section */}
          <div className="grid grid-cols-2 gap-4">
            <NumberInput
              label="Cooldown (minutes)"
              value={rule.cooldown_minutes ?? 10}
              onChange={(v) => onChange({ ...rule, cooldown_minutes: v })}
              min={0}
              helper="Min time between repeat sends"
              info="Prevents alert spam. Same condition won't re-trigger this rule within this window."
            />
            {quietHoursEnabled && (
              <div className="flex items-end pb-1">
                <Toggle
                  label="Override Quiet Hours"
                  checked={rule.override_quiet ?? false}
                  onChange={(v) => onChange({ ...rule, override_quiet: v })}
                  helper="Deliver during quiet hours"
                />
              </div>
            )}
          </div>

          {/* Rule statistics */}
          {ruleStats && (
            <div className="flex items-center gap-4 text-xs text-slate-500">
              <span>Last fired: {formatRelativeTime(ruleStats.last_fired)}</span>
              <span>Last tested: {formatRelativeTime(ruleStats.last_test)}</span>
              <span>Total fires: {ruleStats.fire_count}</span>
            </div>
          )}

          {/* Example message */}
          {rule.trigger_type !== 'schedule' && (
            <div className="space-y-2">
              <label className="text-xs text-slate-500 uppercase tracking-wide">Example Message</label>
              <div className="p-3 bg-[#1e2a3a]/50 rounded-lg border border-[#1e2a3a]">
                <p className="text-sm text-slate-300 font-mono">{getExampleMessage()}</p>
              </div>
              <p className="text-xs text-slate-600">This is an example of what this rule would send.</p>
            </div>
          )}
        </div>
      )}
    </div>
  )
}

// Main Notifications Page Component
export default function Notifications() {
  const [config, setConfig] = useState<NotificationsConfig | null>(null)
  const [originalConfig, setOriginalConfig] = useState<NotificationsConfig | null>(null)
  const [categories, setCategories] = useState<AlertCategory[]>([])
  const [loading, setLoading] = useState(true)
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [success, setSuccess] = useState<string | null>(null)
  const [testResult, setTestResult] = useState<TestResult | null>(null)
  const [testDialog, setTestDialog] = useState<{ open: boolean; ruleIndex: number; loading: boolean; action: string }>({ open: false, ruleIndex: -1, loading: false, action: '' })
  const [showTemplates, setShowTemplates] = useState(false)
  const [hasChanges, setHasChanges] = useState(false)

  const fetchConfig = useCallback(async () => {
    try {
      const [configRes, categoriesRes] = await Promise.all([
        fetch('/api/config/notifications'),
        fetch('/api/notifications/categories'),
      ])
      if (!configRes.ok) throw new Error('Failed to fetch notifications config')
      const configData = await configRes.json()
      const categoriesData = await categoriesRes.json()
      setConfig(configData)
      setOriginalConfig(JSON.parse(JSON.stringify(configData)))
      setCategories(categoriesData)
      setHasChanges(false)
      setError(null)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unknown error')
    } finally {
      setLoading(false)
    }
  }, [])

  useEffect(() => {
    document.title = 'Notifications - MeshAI'
    fetchConfig()
  }, [fetchConfig])

  useEffect(() => {
    if (config && originalConfig) {
      setHasChanges(JSON.stringify(config) !== JSON.stringify(originalConfig))
    }
  }, [config, originalConfig])

  const saveConfig = async () => {
    if (!config) return

    setSaving(true)
    setError(null)
    setSuccess(null)

    try {
      const res = await fetch('/api/config/notifications', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(config),
      })

      const result = await res.json()

      if (!res.ok) {
        throw new Error(result.detail || 'Save failed')
      }

      setSuccess('Notifications config saved successfully')
      setOriginalConfig(JSON.parse(JSON.stringify(config)))
      setHasChanges(false)
      setTimeout(() => setSuccess(null), 3000)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Save failed')
    } finally {
      setSaving(false)
    }
  }

  const discardChanges = () => {
    if (originalConfig) {
      setConfig(JSON.parse(JSON.stringify(originalConfig)))
      setHasChanges(false)
    }
  }

  const createDefaultRule = (): NotificationRuleConfig => ({
    name: '',
    enabled: true,
    trigger_type: 'condition',
    categories: [],
    min_severity: 'routine',
    schedule_frequency: 'daily',
    schedule_time: '07:00',
    schedule_time_2: '19:00',
    schedule_days: ['monday'],
    message_type: 'mesh_health_summary',
    custom_message: '',
    delivery_type: '',
    broadcast_channel: 0,
    node_ids: [],
    smtp_host: '',
    smtp_port: 587,
    smtp_user: '',
    smtp_password: '',
    smtp_tls: true,
    from_address: '',
    recipients: [],
    webhook_url: '',
    webhook_headers: {},
    cooldown_minutes: 10,
    override_quiet: false,
  })

  const addRule = () => {
    if (!config) return
    setConfig({ ...config, rules: [...(config.rules || []), createDefaultRule()] })
  }

  const addFromTemplate = (templateId: string) => {
    if (!config) return
    const template = RULE_TEMPLATES.find(t => t.id === templateId)
    if (!template) return
    setConfig({ ...config, rules: [...(config.rules || []), { ...template.rule }] })
    setShowTemplates(false)
  }

  const duplicateRule = (index: number) => {
    if (!config) return
    const original = config.rules[index]
    const duplicate = { ...JSON.parse(JSON.stringify(original)), name: `${original.name} (copy)` }
    const newRules = [...config.rules]
    newRules.splice(index + 1, 0, duplicate)
    setConfig({ ...config, rules: newRules })
  }

  const testRule = async (index: number) => {
    setTestDialog({ open: true, ruleIndex: index, loading: true, action: '' })
    try {
      const res = await fetch(`/api/notifications/rules/${index}/test`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'preview' })
      })
      const result = await res.json()
      setTestResult(result)
      setTestDialog(d => ({ ...d, loading: false }))
    } catch {
      setTestResult({ success: false, message: 'Failed to get preview' })
      setTestDialog(d => ({ ...d, loading: false }))
    }
  }

  const sendTestAction = async (action: string) => {
    const index = testDialog.ruleIndex
    setTestDialog(d => ({ ...d, loading: true, action }))
    try {
      const res = await fetch(`/api/notifications/rules/${index}/test`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action })
      })
      const result = await res.json()
      setTestResult(result)
      setTestDialog(d => ({ ...d, loading: false }))
    } catch {
      setTestResult({ success: false, message: `Failed to ${action}` })
      setTestDialog(d => ({ ...d, loading: false }))
    }
  }

  const closeTestDialog = () => {
    setTestDialog({ open: false, ruleIndex: -1, loading: false, action: '' })
    setTestResult(null)
  }

  if (loading) {
    return (
      <div className="flex items-center justify-center h-64">
        <div className="text-slate-400">Loading notifications config...</div>
      </div>
    )
  }

  if (!config) {
    return (
      <div className="flex items-center justify-center h-64">
        <div className="text-red-400">Failed to load notifications config</div>
      </div>
    )
  }

  return (
    <div className="max-w-4xl mx-auto space-y-6">
      {/* Test Dialog */}
      {testDialog.open && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
          <div className="bg-[#1a2332] border border-[#2a3a4a] rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-[85vh] overflow-auto">
            <div className="p-4 border-b border-[#2a3a4a] flex items-center justify-between sticky top-0 bg-[#1a2332]">
              <h3 className="text-lg font-semibold">Test Notification Rule</h3>
              <button onClick={closeTestDialog} className="text-slate-500 hover:text-slate-300">
                <X size={20} />
              </button>
            </div>
            <div className="p-4 space-y-4">
              {testDialog.loading ? (
                <div className="flex items-center justify-center py-8">
                  <RefreshCw size={20} className="animate-spin text-slate-400 mr-2" />
                  <div className="text-slate-400">
                    {testDialog.action ? `${testDialog.action.replace('_', ' ').replace('send ', 'Sending ')}...` : 'Loading current data...'}
                  </div>
                </div>
              ) : testResult ? (
                <>
                  {/* Section 1: Current Data */}
                  <div className="space-y-2">
                    <div className="text-sm font-medium text-slate-400 uppercase tracking-wide">Current Data</div>
                    {testResult.live_data_summary && testResult.live_data_summary.length > 0 ? (
                      <div className="p-3 bg-slate-800/50 rounded space-y-1">
                        {testResult.live_data_summary.map((line, i) => (
                          <div
                            key={i}
                            className={`text-sm font-mono ${line.startsWith('[!]') ? 'text-amber-400' : ''}`}
                          >
                            {line}
                          </div>
                        ))}
                      </div>
                    ) : (
                      <div className="p-3 bg-slate-800/50 rounded text-sm text-slate-500">
                        No live data available for this rule's categories
                      </div>
                    )}
                  </div>

                  {/* Section 2: Alert Conditions */}
                  <div className="space-y-2">
                    <div className="text-sm font-medium text-slate-400 uppercase tracking-wide">Rule Matching</div>
                    <div className="flex items-center gap-2 flex-wrap">
                      {testResult.conditions_matched && testResult.conditions_matched > 0 ? (
                        <span className="px-2 py-1 bg-green-500/20 text-green-400 rounded text-sm">
                          {testResult.conditions_matched} condition{testResult.conditions_matched !== 1 ? 's' : ''} match - this rule WOULD fire
                        </span>
                      ) : (
                        <span className="px-2 py-1 bg-slate-700 text-slate-400 rounded text-sm">
                          No conditions trigger this rule right now
                        </span>
                      )}
                      {testResult.conditions_below_threshold && testResult.conditions_below_threshold > 0 && (
                        <span className="px-2 py-1 bg-yellow-500/20 text-yellow-400 rounded text-sm">
                          {testResult.conditions_below_threshold} below threshold
                        </span>
                      )}
                    </div>

                    {/* Near-miss explanation */}
                    {testResult.conditions_below_threshold && testResult.conditions_below_threshold > 0 && (
                      <div className="p-3 bg-yellow-500/10 border border-yellow-500/30 rounded text-sm space-y-2">
                        <div className="text-yellow-300">{testResult.below_threshold_summary}</div>
                        {testResult.below_threshold_events && testResult.below_threshold_events.length > 0 && (
                          <div className="space-y-1 text-yellow-200/80">
                            {testResult.below_threshold_events.slice(0, 3).map((evt, i) => (
                              <div key={i} className="flex items-center gap-2">
                                <span className="text-xs px-1.5 py-0.5 bg-yellow-500/20 rounded">{evt.severity}</span>
                                <span>{evt.headline}</span>
                              </div>
                            ))}
                          </div>
                        )}
                        {testResult.suggestion && (
                          <div className="text-yellow-400 text-xs mt-2">Tip: {testResult.suggestion}</div>
                        )}
                      </div>
                    )}
                  </div>

                  {/* Section 3: Preview Messages */}
                  <div className="space-y-2">
                    <div className="text-sm font-medium text-slate-400 uppercase tracking-wide">
                      {testResult.is_example ? 'Example Messages' : 'Messages That Would Fire'}
                    </div>
                    {testResult.preview_messages?.map((msg, i) => (
                      <div key={i} className="p-3 bg-slate-800 rounded text-sm font-mono break-words">
                        {msg}
                      </div>
                    ))}
                  </div>

                  {/* Delivery result */}
                  {testResult.delivered !== undefined && testResult.delivery_result && (
                    <div className={`p-3 rounded text-sm ${
                      testResult.delivered
                        ? 'bg-green-500/10 border border-green-500/30 text-green-400'
                        : 'bg-red-500/10 border border-red-500/30 text-red-400'
                    }`}>
                      <div className="flex items-start gap-2">
                        {testResult.delivered ? <Check size={16} className="mt-0.5" /> : <X size={16} className="mt-0.5" />}
                        <div>
                          <div>{testResult.delivery_result}</div>
                          {testResult.delivery_error && (
                            <div className="mt-1 text-red-300">{testResult.delivery_error}</div>
                          )}
                        </div>
                      </div>
                    </div>
                  )}

                  {/* Legacy format support */}
                  {testResult.message && !testResult.preview_messages && (
                    <div className={`p-3 rounded text-sm ${testResult.success ? 'bg-green-500/10 text-green-400' : 'bg-red-500/10 text-red-400'}`}>
                      {testResult.message}
                    </div>
                  )}
                </>
              ) : null}
            </div>
            <div className="p-4 border-t border-[#2a3a4a] flex justify-between sticky bottom-0 bg-[#1a2332]">
              <button
                onClick={closeTestDialog}
                className="px-4 py-2 text-slate-400 hover:text-slate-200"
              >
                Close
              </button>
              {testResult && !testResult.delivered && (
                <div className="flex gap-2">
                  {!testResult.delivery_method ? (
                    <span className="px-3 py-2 text-amber-400 text-sm">
                      Configure a delivery method to send test messages
                    </span>
                  ) : (
                    <>
                      {testResult.live_data_summary && testResult.live_data_summary.length > 0 && (
                        <button
                          onClick={() => sendTestAction('send_status')}
                          disabled={testDialog.loading}
                          className="px-3 py-2 bg-slate-700 hover:bg-slate-600 rounded text-sm disabled:opacity-50"
                          title="Send current conditions summary"
                        >
                          Send Current Conditions
                        </button>
                      )}
                      <button
                        onClick={() => sendTestAction('send_test')}
                        disabled={testDialog.loading}
                        className="px-3 py-2 bg-slate-700 hover:bg-slate-600 rounded text-sm disabled:opacity-50"
                        title="Send example alert message"
                      >
                        Send Example Alert
                      </button>
                      {testResult.can_send_live && (
                        <button
                          onClick={() => sendTestAction('send_live')}
                          disabled={testDialog.loading}
                          className="px-3 py-2 bg-accent hover:bg-accent/80 rounded text-sm disabled:opacity-50"
                          title="Send actual live alert"
                        >
                          Send Live Alert
                        </button>
                      )}
                    </>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* Header */}
      <div className="flex items-center justify-between">
        <div>
          <p className="text-sm text-slate-500">
            Alert delivery and scheduled reports. Rules define what triggers a notification and where it gets sent.
          </p>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={fetchConfig}
            className="p-2 text-slate-400 hover:text-slate-200 hover:bg-bg-hover rounded transition-colors"
            title="Refresh"
          >
            <RefreshCw size={18} />
          </button>
          <button
            onClick={discardChanges}
            disabled={!hasChanges}
            className="flex items-center gap-2 px-3 py-2 text-slate-400 hover:text-slate-200 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
          >
            <RotateCcw size={16} />
            Discard
          </button>
          <button
            onClick={saveConfig}
            disabled={saving || !hasChanges}
            className="flex items-center gap-2 px-4 py-2 bg-accent hover:bg-accent/80 disabled:bg-slate-700 disabled:cursor-not-allowed rounded text-white transition-colors"
          >
            <Save size={16} />
            {saving ? 'Saving...' : 'Save'}
          </button>
        </div>
      </div>

      {/* Status messages */}
      {error && (
        <div className="p-3 rounded-lg text-sm bg-red-500/10 text-red-400 border border-red-500/20">
          {error}
        </div>
      )}
      {success && (
        <div className="p-3 rounded-lg text-sm bg-green-500/10 text-green-400 border border-green-500/20">
          <Check size={14} className="inline mr-2" />
          {success}
        </div>
      )}

      {/* Main content */}
      <div className="bg-bg-card border border-border rounded-lg p-6 space-y-6">
        <Toggle
          label="Enable Notifications"
          checked={config.enabled}
          onChange={(v) => setConfig({ ...config, enabled: v })}
          helper="Master switch for all notification delivery"
          info="When disabled, no alerts or scheduled messages will be delivered. Alerts still get recorded to history."
        />

        {config.enabled && (
          <>
            {/* Quiet Hours Section */}
            <div className="space-y-3 p-4 bg-[#0a0e17] rounded-lg border border-[#1e2a3a]">
              <div className="flex items-center gap-2">
                <Moon size={14} className="text-slate-400" />
                <label className="text-xs text-slate-500 uppercase tracking-wide">Quiet Hours</label>
              </div>

              <Toggle
                label="Enable Quiet Hours"
                checked={config.quiet_hours_enabled ?? true}
                onChange={(v) => setConfig({ ...config, quiet_hours_enabled: v })}
                helper="Suppress non-emergency alerts during sleeping hours"
                info="When enabled, ROUTINE alerts are suppressed during quiet hours. PRIORITY and IMMEDIATE always deliver."
              />

              {config.quiet_hours_enabled && (
                <>
                  <div className="grid grid-cols-2 gap-4">
                    <TimeInput
                      label="Start Time"
                      value={config.quiet_hours_start || '22:00'}
                      onChange={(v) => setConfig({ ...config, quiet_hours_start: v })}
                      helper="When quiet hours begin"
                    />
                    <TimeInput
                      label="End Time"
                      value={config.quiet_hours_end || '06:00'}
                      onChange={(v) => setConfig({ ...config, quiet_hours_end: v })}
                      helper="When quiet hours end"
                    />
                  </div>
                  <p className="text-xs text-slate-600">
                    Emergency alerts and rules with "Override Quiet Hours" enabled always deliver.
                  </p>
                </>
              )}
            </div>

            {/* Rules Section */}
            <div className="space-y-3">
              <div className="flex items-center justify-between">
                <label className="flex items-center text-xs text-slate-500 uppercase tracking-wide">
                  Notification Rules
                  <InfoButton info="Each rule is self-contained: define what triggers it (condition or schedule), where to send it (mesh, email, webhook), and behavior settings." />
                </label>
                <span className="text-xs text-slate-500">
                  {config.rules?.length || 0} rule{(config.rules?.length || 0) !== 1 ? 's' : ''}
                </span>
              </div>

              {(config.rules || []).map((rule, i) => (
                <NotificationRuleCard
                  key={i}
                  rule={rule}
                  ruleIndex={i}
                  categories={categories}
                  quietHoursEnabled={config.quiet_hours_enabled ?? true}
                  onChange={(r) => {
                    const newRules = [...(config.rules || [])]
                    newRules[i] = r
                    setConfig({ ...config, rules: newRules })
                  }}
                  onDelete={() => {
                    if (confirm(`Delete rule "${rule.name || 'New Rule'}"?`)) {
                      setConfig({ ...config, rules: (config.rules || []).filter((_, j) => j !== i) })
                    }
                  }}
                  onDuplicate={() => duplicateRule(i)}
                  onTest={() => testRule(i)}
                />
              ))}

              <div className="flex gap-2">
                <button
                  onClick={addRule}
                  className="flex-1 py-3 border border-dashed border-[#1e2a3a] rounded-lg text-slate-500 hover:text-slate-300 hover:border-accent flex items-center justify-center gap-2 transition-colors"
                >
                  <Plus size={16} /> Add Rule
                </button>
                <div className="relative">
                  <button
                    onClick={() => setShowTemplates(!showTemplates)}
                    className="py-3 px-4 border border-dashed border-[#1e2a3a] rounded-lg text-slate-500 hover:text-slate-300 hover:border-accent flex items-center gap-2 transition-colors"
                  >
                    <Layers size={16} /> Add from Template
                  </button>
                  {showTemplates && (
                    <>
                      <div className="fixed inset-0 z-40" onClick={() => setShowTemplates(false)} />
                      <div className="absolute right-0 top-full mt-2 z-50 w-80 bg-[#1a2332] border border-[#2a3a4a] rounded-lg shadow-xl overflow-hidden">
                        <div className="p-2 border-b border-[#2a3a4a] text-xs text-slate-500 uppercase">Rule Templates</div>
                        {RULE_TEMPLATES.map((t) => (
                          <button
                            key={t.id}
                            onClick={() => addFromTemplate(t.id)}
                            className="w-full p-3 text-left hover:bg-[#2a3a4a] transition-colors"
                          >
                            <div className="font-medium text-slate-200">{t.name}</div>
                            <div className="text-xs text-slate-500 mt-0.5">{t.description}</div>
                          </button>
                        ))}
                      </div>
                    </>
                  )}
                </div>
              </div>
            </div>
          </>
        )}
      </div>
    </div>
  )
}
