'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import Link from 'next/link'
import { ChevronLeft, Circle, CheckCircle2, Pencil, Trash2, Check, X, Flag, Loader2, Target, Search, Plus, Lightbulb, Paperclip, Sparkles } from 'lucide-react'
import { AttachmentRow, uploadAttachments, deleteAttachment, type Att } from './attachments'

interface Reminder { id: string; title: string; notes: string | null; dueDate: string | null; priority: number | null; topic: string | null; list: string | null; listId: string | null; flagged: boolean; overdue: boolean; pending: boolean; attachments: Att[] }
interface ListOpt { id: string; name: string }

const PRIORITIES = [{ v: 0, label: 'None' }, { v: 1, label: 'High' }, { v: 5, label: 'Medium' }, { v: 9, label: 'Low' }]

function toLocalInput(iso: string | null): string {
  if (!iso) return ''
  const d = new Date(iso)
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}
function dueLabel(iso: string | null): string {
  if (!iso) return ''
  return new Date(iso).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' })
}
// New reminders default to today — the next full hour, so they're due today
// but never instantly overdue.
function defaultDue(): string {
  const d = new Date()
  d.setMinutes(0, 0, 0)
  d.setHours(d.getHours() + 1)
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}

export function RemindersList() {
  const [reminders, setReminders] = useState<Reminder[]>([])
  const [lists, setLists] = useState<ListOpt[]>([])
  const [loaded, setLoaded] = useState(false)
  const [editing, setEditing] = useState<string | null>(null)
  const [form, setForm] = useState<{ title: string; dueDate: string; priority: number; listId: string }>({ title: '', dueDate: '', priority: 0, listId: '' })
  const [query, setQuery] = useState('')
  const [groupByTopic, setGroupByTopic] = useState(false)
  const [organizing, setOrganizing] = useState(false)
  const [newTitle, setNewTitle] = useState('')
  const [newDue, setNewDue] = useState(defaultDue)
  const [staged, setStaged] = useState<{ file: File; url: string }[]>([])
  const fileInputRef = useRef<HTMLInputElement>(null)

  const load = useCallback(async () => {
    const res = await fetch('/api/reminders', { cache: 'no-store' })
    if (res.ok) { const d = await res.json(); setReminders(d.reminders || []); setLists(d.lists || []) }
    setLoaded(true)
  }, [])
  useEffect(() => { load() }, [load])

  // ── app-only photos (EventKit can't sync attachments to Apple) ──────────
  const uploadImages = async (id: string, files: File[]) => {
    const atts = await uploadAttachments('reminder', id, files)
    if (atts.length > 0) setReminders(rs => rs.map(r => r.id === id ? { ...r, attachments: [...(r.attachments || []), ...atts] } : r))
  }
  const delImage = async (reminderId: string, attId: string) => {
    setReminders(rs => rs.map(r => r.id === reminderId ? { ...r, attachments: (r.attachments || []).filter(a => a.id !== attId) } : r))
    await deleteAttachment(attId)
  }
  const stageFiles = (files: File[]) => {
    if (files.length === 0) return
    setStaged(prev => [...prev, ...files.map(f => ({ file: f, url: URL.createObjectURL(f) }))])
  }
  const removeStaged = (url: string) => {
    URL.revokeObjectURL(url)
    setStaged(prev => prev.filter(x => x.url !== url))
  }
  useEffect(() => {
    const onPaste = (e: ClipboardEvent) => {
      const files = Array.from(e.clipboardData?.items || [])
        .filter(item => item.kind === 'file' && item.type.startsWith('image/'))
        .map(item => item.getAsFile())
        .filter((f): f is File => f !== null)
      if (files.length === 0) return
      e.preventDefault()
      if (editing) uploadImages(editing, files)
      else stageFiles(files)
    }
    document.addEventListener('paste', onPaste)
    return () => document.removeEventListener('paste', onPaste)
  })
  const onPickImages = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || [])
    e.target.value = ''
    if (editing) uploadImages(editing, files)
    else stageFiles(files)
  }

  const add = async () => {
    const title = newTitle.trim()
    if (!title) return
    setNewTitle('')
    const res = await fetch('/api/reminders', {
      method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title, dueDate: newDue ? new Date(newDue).toISOString() : null }),
    })
    if (res.ok && staged.length > 0) {
      const { id } = await res.json()
      await uploadAttachments('reminder', id, staged.map(x => x.file))
      staged.forEach(x => URL.revokeObjectURL(x.url))
      setStaged([])
    }
    setNewDue(defaultDue())
    load()
  }
  // Checked reminders linger (struck through) for a beat before leaving the
  // list, so a misclick can be unchecked.
  const GRACE_MS = 2500
  const [justDone, setJustDone] = useState<Set<string>>(new Set())
  const graceTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map())
  const complete = async (id: string) => {
    setJustDone(s => new Set(s).add(id))
    graceTimers.current.set(id, setTimeout(() => {
      setReminders(rs => rs.filter(r => r.id !== id))
      setJustDone(s => { const n = new Set(s); n.delete(id); return n })
      graceTimers.current.delete(id)
    }, GRACE_MS))
    await fetch(`/api/reminders/${id}/complete`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' })
  }
  const uncomplete = async (id: string) => {
    const tm = graceTimers.current.get(id)
    if (tm) { clearTimeout(tm); graceTimers.current.delete(id) }
    setJustDone(s => { const n = new Set(s); n.delete(id); return n })
    await fetch(`/api/reminders/${id}/complete`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ completed: false }) })
  }
  const del = async (id: string) => {
    if (!confirm('Delete this reminder (also in Apple)?')) return
    setReminders(rs => rs.filter(r => r.id !== id))
    await fetch(`/api/reminders/${id}`, { method: 'DELETE' })
  }
  const [added, setAdded] = useState<Set<string>>(new Set())
  const addToFocus = async (id: string) => {
    setAdded(s => new Set(s).add(id))
    await fetch('/api/focus', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reminderId: id }) })
  }
  // Reverse of the thought→todo convert: this "task" was really just an idea.
  // Creates a thought from the content, then deletes the reminder (Apple too).
  const toThought = async (r: Reminder) => {
    if (!confirm(`Move this to Thoughts? The reminder will be deleted (also in Apple).\n\n“${r.title}”`)) return
    const body = r.notes ? `${r.title}\n\n${r.notes}` : r.title
    const res = await fetch('/api/thoughts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ body }) })
    if (!res.ok) return
    setReminders(rs => rs.filter(x => x.id !== r.id))
    await fetch(`/api/reminders/${r.id}`, { method: 'DELETE' })
  }
  const startEdit = (r: Reminder) => {
    setEditing(r.id)
    setForm({ title: r.title, dueDate: toLocalInput(r.dueDate), priority: r.priority ?? 0, listId: r.listId || '' })
  }
  const saveEdit = async (id: string) => {
    await fetch(`/api/reminders/${id}`, {
      method: 'PATCH', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title: form.title, dueDate: form.dueDate || null, priority: form.priority, listId: form.listId || null }),
    })
    setEditing(null); load()
  }
  // Topics are assigned by the organize pass (Claude on the Mac); kick it and
  // reload once it's had time to run.
  const organize = async () => {
    setOrganizing(true)
    await fetch('/api/organize', { method: 'POST' })
    setTimeout(() => { load(); setOrganizing(false) }, 15000)
  }

  const q = query.trim().toLowerCase()
  const visible = q
    ? reminders.filter(r => r.title.toLowerCase().includes(q) || (r.list || '').toLowerCase().includes(q))
    : reminders

  // Optional AI-topic grouping (a lens — the default flat view stays due-date
  // ordered). Untopiced reminders fall into "Other", sorted last.
  const TOPIC_OTHER = '￿Other'
  const topicGroups = new Map<string, Reminder[]>()
  for (const r of visible) { const k = r.topic || TOPIC_OTHER; if (!topicGroups.has(k)) topicGroups.set(k, []); topicGroups.get(k)!.push(r) }
  const topicKeys = [...topicGroups.keys()].sort()
  const anyTopics = visible.some(r => r.topic)

  const row = (r: Reminder) => (
    <li key={r.id} className="rounded-xl border border-border bg-card p-3">
      {editing === r.id ? (
        <div className="space-y-2">
          <input value={form.title} onChange={e => setForm(f => ({ ...f, title: e.target.value }))} className="w-full rounded-lg border border-input bg-background px-3 h-10 text-base focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" />
          <input type="datetime-local" value={form.dueDate} onChange={e => setForm(f => ({ ...f, dueDate: e.target.value }))} className="w-full rounded-lg border border-input bg-background px-3 h-10 text-base focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" />
          <div className="flex gap-2">
            <select value={form.priority} onChange={e => setForm(f => ({ ...f, priority: Number(e.target.value) }))} className="flex-1 rounded-lg border border-input bg-background px-2 h-10 text-base">
              {PRIORITIES.map(p => <option key={p.v} value={p.v}>{p.label}</option>)}
            </select>
            <select value={form.listId} onChange={e => setForm(f => ({ ...f, listId: e.target.value }))} className="flex-1 rounded-lg border border-input bg-background px-2 h-10 text-base">
              <option value="">(default list)</option>
              {lists.map(l => <option key={l.id} value={l.id}>{l.name}</option>)}
            </select>
          </div>
          <AttachmentRow atts={r.attachments || []} onDelete={id => delImage(r.id, id)} />
          <div className="flex gap-2 items-center">
            <button onClick={() => fileInputRef.current?.click()} className="inline-flex items-center gap-1 text-sm text-muted-foreground px-2 h-8 rounded hover:bg-muted"><Paperclip className="h-4 w-4" /> Add image</button>
            <div className="ml-auto flex gap-2 justify-end">
            <button onClick={() => setEditing(null)} className="inline-flex items-center gap-1 text-sm text-muted-foreground px-2 h-8"><X className="h-4 w-4" /> Cancel</button>
            <button onClick={() => saveEdit(r.id)} className="inline-flex items-center gap-1 text-sm rounded-lg bg-primary text-primary-foreground px-3 h-8"><Check className="h-4 w-4" /> Save</button>
            </div>
          </div>
        </div>
      ) : (
        <div className="flex items-start gap-2">
          {justDone.has(r.id) ? (
            <button onClick={() => uncomplete(r.id)} className="mt-0.5 text-emerald-600" aria-label="Undo complete">
              <CheckCircle2 className="h-5 w-5" />
            </button>
          ) : (
            <button onClick={() => complete(r.id)} className="mt-0.5 text-muted-foreground hover:text-primary" aria-label="Complete">
              <Circle className="h-5 w-5" />
            </button>
          )}
          <div className="min-w-0 flex-1">
            <div className="text-sm flex items-center gap-1.5">
              <span className={`line-clamp-3 break-words ${justDone.has(r.id) ? 'line-through text-muted-foreground' : ''}`} title={r.title}>{r.title}</span>
              {r.flagged && <Flag className="h-3 w-3 text-amber-500 shrink-0" />}
              {r.pending && <Loader2 className="h-3 w-3 animate-spin text-muted-foreground shrink-0" />}
            </div>
            <div className="text-xs text-muted-foreground mt-0.5 flex items-center gap-2">
              {r.list && <span>{r.list}</span>}
              {r.dueDate && <span className={r.overdue ? 'text-destructive' : ''}>{dueLabel(r.dueDate)}</span>}
            </div>
            <AttachmentRow atts={r.attachments || []} className="mt-1.5" />
          </div>
          <button onClick={() => addToFocus(r.id)} disabled={added.has(r.id)} className={`p-1.5 rounded hover:bg-muted ${added.has(r.id) ? 'text-primary' : 'text-muted-foreground'}`} aria-label="Add to Focus" title="Add to Focus"><Target className="h-4 w-4" /></button>
          <button onClick={() => toThought(r)} className="p-1.5 rounded hover:bg-muted text-muted-foreground" aria-label="Convert to thought" title="This was really just an idea — move it to Thoughts"><Lightbulb className="h-4 w-4" /></button>
          <button onClick={() => startEdit(r)} className="p-1.5 rounded hover:bg-muted text-muted-foreground" aria-label="Edit"><Pencil className="h-4 w-4" /></button>
          <button onClick={() => del(r.id)} className="p-1.5 rounded hover:bg-muted hover:text-destructive text-muted-foreground" aria-label="Delete"><Trash2 className="h-4 w-4" /></button>
        </div>
      )}
    </li>
  )

  return (
    <div className="min-h-screen max-w-md mx-auto flex flex-col">
      <header className="safe-top px-4 pb-3 flex items-center gap-2">
        <Link href="/" className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground">
          <ChevronLeft className="h-4 w-4" /> Dashboard
        </Link>
        <span className="ml-auto font-semibold">Reminders</span>
      </header>

      <div className="px-4 pb-3 space-y-2">
        <div className="flex gap-2">
          <input
            value={newTitle}
            onChange={e => setNewTitle(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter') add() }}
            placeholder="New reminder…"
            className="flex-1 rounded-lg border border-input bg-background px-3 h-10 text-base focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
          />
          <input
            type="datetime-local"
            value={newDue}
            onChange={e => setNewDue(e.target.value)}
            aria-label="Due date"
            className="w-40 rounded-lg border border-input bg-background px-2 h-10 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
          />
          <button onClick={() => fileInputRef.current?.click()} className="rounded-lg border border-border px-3 h-10 inline-flex items-center text-muted-foreground hover:bg-muted" aria-label="Add image"><Paperclip className="h-4 w-4" /></button>
          <button onClick={add} className="rounded-lg bg-primary text-primary-foreground px-3 h-10 inline-flex items-center" aria-label="Add reminder"><Plus className="h-4 w-4" /></button>
        </div>
        <input ref={fileInputRef} type="file" multiple onChange={onPickImages} className="hidden" />
        {staged.length > 0 && (
          <div className="flex flex-wrap gap-1.5">
            {staged.map(x => (
              <div key={x.url} className="relative">
                {x.file.type.startsWith('image/') ? (
                  // eslint-disable-next-line @next/next/no-img-element
                  <img src={x.url} alt="" className="w-14 h-14 rounded-md object-cover border border-border" />
                ) : (
                  <span className="inline-flex items-center text-xs rounded-lg border border-border bg-background px-2 py-1.5 text-muted-foreground max-w-44 truncate">{x.file.name}</span>
                )}
                <button onClick={() => removeStaged(x.url)} className="absolute -top-1.5 -right-1.5 bg-background border border-border rounded-full p-0.5" aria-label="Remove attachment"><X className="h-3 w-3" /></button>
              </div>
            ))}
          </div>
        )}
        <div className="flex items-center gap-2">
          <div className="inline-flex rounded-full border border-border overflow-hidden text-xs">
            <button onClick={() => setGroupByTopic(false)} className={`px-2.5 py-1 ${!groupByTopic ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}>Due date</button>
            <button onClick={() => setGroupByTopic(true)} className={`px-2.5 py-1 ${groupByTopic ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}>By topic</button>
          </div>
          {groupByTopic && !anyTopics && <span className="text-xs text-muted-foreground">No topics yet — Organize →</span>}
          <button onClick={organize} disabled={organizing} className="ml-auto inline-flex items-center gap-1.5 text-sm rounded-lg border border-border px-2.5 h-8 hover:bg-muted disabled:opacity-50" title="Group by topic with AI">
            <Sparkles className={`h-4 w-4 ${organizing ? 'animate-pulse' : ''}`} /> {organizing ? 'Organizing…' : 'Organize'}
          </button>
        </div>
        <div className="relative">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" />
          <input
            type="search"
            value={query}
            onChange={e => setQuery(e.target.value)}
            placeholder="Search reminders…"
            className="w-full rounded-lg border border-input bg-background pl-9 pr-9 h-10 text-base focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
          />
          {query && (
            <button
              onClick={() => setQuery('')}
              className="absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded text-muted-foreground hover:text-foreground"
              aria-label="Clear search"
            >
              <X className="h-4 w-4" />
            </button>
          )}
        </div>
      </div>

      <main className="flex-1 px-4 pb-10">
        {!loaded ? (
          <div className="py-10 text-center"><Loader2 className="h-5 w-5 animate-spin mx-auto text-muted-foreground" /></div>
        ) : reminders.length === 0 ? (
          <p className="text-sm text-muted-foreground text-center py-10">No open reminders 🎉</p>
        ) : visible.length === 0 ? (
          <p className="text-sm text-muted-foreground text-center py-10">No reminders match &ldquo;{query.trim()}&rdquo;</p>
        ) : groupByTopic ? (
          <div className="space-y-4">
            {topicKeys.map(key => {
              const label = key === TOPIC_OTHER ? 'Other' : key
              const items = topicGroups.get(key)!
              return (
                <section key={key} className="space-y-2">
                  <div className="px-1 text-sm font-semibold flex items-center gap-2">
                    {label}
                    <span className="text-xs rounded-full bg-muted px-2 py-0.5 text-muted-foreground font-normal">{items.length}</span>
                  </div>
                  <ul className="space-y-2">{items.map(row)}</ul>
                </section>
              )
            })}
          </div>
        ) : (
          <ul className="space-y-2">{visible.map(row)}</ul>
        )}
      </main>
    </div>
  )
}
