'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import Link from 'next/link'
import { ChevronLeft, Target, Circle, CheckCircle2, X, Plus, Check, Eye, EyeOff, Paperclip, Copy, ClipboardList, Sparkles, Users, Lock } from 'lucide-react'
import { AttachmentRow, uploadAttachments, deleteAttachment, type Att } from './attachments'

interface PinMeta { shared: boolean; mine: boolean }
interface ReminderPin extends PinMeta { pinId: string; kind: 'reminder'; id: string; title: string; done: boolean; topic: string | null; dueDate: string | null; list: string | null; attachments: Att[] }
interface ItemPin extends PinMeta { pinId: string; kind: 'item'; id: string; title: string; done: boolean; topic: string | null; list: string | null; listId: string }
interface ListItem { id: string; title: string; done: boolean; optional: boolean; topic: string | null }
interface ListPin extends PinMeta { pinId: string; kind: 'list'; id: string; name: string; items: ListItem[] }
type Pin = ReminderPin | ItemPin | ListPin
type TaskPin = ReminderPin | ItemPin

const NO_LIST = 'Reminders' // bucket label for pinned reminders with no Apple list
const OTHER = 'Other' // bucket label for tasks with no AI topic yet
const SENT = '￿' // sentinel prefix: sorts a bucket last, stripped for display

// Full-page Focus: a pinboard. Pinned reminders and pinned single list items are
// grouped by their list (so you can see where each came from); pinned whole
// lists each render as their own expanded section. Focus owns nothing —
// toggling/attaching acts on the underlying record, removing only unpins.
export function FocusPage() {
  const [pins, setPins] = useState<Pin[]>([])
  const [loaded, setLoaded] = useState(false)
  const [draft, setDraft] = useState('')
  const [showDone, setShowDone] = useState(false)
  const [groupBy, setGroupBy] = useState<'topic' | 'list'>('topic')
  const [copied, setCopied] = useState(false)
  const [organizing, setOrganizing] = useState(false)
  const [editing, setEditing] = useState<string | null>(null) // pinId being renamed
  const [editText, setEditText] = useState('')
  const attachTargetRef = useRef<string | null>(null)
  const fileInputRef = useRef<HTMLInputElement>(null)

  const load = useCallback(async () => {
    const res = await fetch('/api/focus', { cache: 'no-store' })
    if (res.ok) setPins((await res.json()).pins || [])
    setLoaded(true)
  }, [])
  useEffect(() => {
    load()
    const t = setInterval(load, 12000)
    return () => clearInterval(t)
  }, [load])

  const tasks = pins.filter((p): p is TaskPin => p.kind === 'reminder' || p.kind === 'item')
  const lists = pins.filter((p): p is ListPin => p.kind === 'list')

  // Just-checked tasks linger (struck through) for a beat so a misclick can be
  // undone before they drop into the hidden-done pile.
  const GRACE_MS = 2500
  const [recentlyDone, setRecentlyDone] = useState<Set<string>>(new Set())
  const graceTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map())

  const pickFor = (reminderId: string) => { attachTargetRef.current = reminderId; fileInputRef.current?.click() }
  const onPickFiles = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || [])
    e.target.value = ''
    const target = attachTargetRef.current
    if (!target || files.length === 0) return
    const atts = await uploadAttachments('reminder', target, files)
    if (atts.length > 0) setPins(ps => ps.map(p => p.kind === 'reminder' && p.id === target ? { ...p, attachments: [...(p.attachments || []), ...atts] } : p))
  }
  const delAtt = async (reminderId: string, attId: string) => {
    setPins(ps => ps.map(p => p.kind === 'reminder' && p.id === reminderId ? { ...p, attachments: (p.attachments || []).filter(a => a.id !== attId) } : p))
    await deleteAttachment(attId)
  }

  const add = async () => {
    if (!draft.trim()) return
    await fetch('/api/focus', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: draft.trim() }) })
    setDraft(''); load()
  }
  // Checking off a pin acts on the canonical record (reminder or list item).
  const toggleTask = async (p: TaskPin) => {
    const next = !p.done
    setPins(ps => ps.map(x => x.pinId === p.pinId ? { ...x, done: next } : x))
    if (next) {
      setRecentlyDone(s => new Set(s).add(p.pinId))
      graceTimers.current.set(p.pinId, setTimeout(() => {
        setRecentlyDone(s => { const n = new Set(s); n.delete(p.pinId); return n })
        graceTimers.current.delete(p.pinId)
      }, GRACE_MS))
    } else {
      const tm = graceTimers.current.get(p.pinId)
      if (tm) { clearTimeout(tm); graceTimers.current.delete(p.pinId) }
      setRecentlyDone(s => { const n = new Set(s); n.delete(p.pinId); return n })
    }
    if (p.kind === 'reminder') {
      await fetch(`/api/reminders/${p.id}/complete`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ completed: next }) })
    } else {
      await fetch(`/api/checklist-items/${p.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ done: next }) })
    }
    load()
  }
  // Toggle an item inside a pinned whole list.
  const toggleListItem = async (listId: string, item: ListItem) => {
    const next = !item.done
    setPins(ps => ps.map(x => x.kind === 'list' && x.id === listId ? { ...x, items: x.items.map(i => i.id === item.id ? { ...i, done: next } : i) } : x))
    await fetch(`/api/checklist-items/${item.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ done: next }) })
    load()
  }
  const unpin = async (pinId: string) => {
    setPins(ps => ps.filter(p => p.pinId !== pinId))
    await fetch(`/api/focus/${pinId}`, { method: 'DELETE' })
    load()
  }
  // Rename acts on the canonical record (the reminder — pushed to Apple — or the
  // list item), not on the pin.
  const startEdit = (p: TaskPin) => { setEditing(p.pinId); setEditText(p.title) }
  const saveEdit = async (p: TaskPin) => {
    const title = editText.trim()
    setEditing(null)
    if (!title || title === p.title) return
    setPins(ps => ps.map(x => x.pinId === p.pinId ? { ...x, title } : x))
    const url = p.kind === 'reminder' ? `/api/reminders/${p.id}` : `/api/checklist-items/${p.id}`
    await fetch(url, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title }) })
    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 clearDone = async () => {
    const n = tasks.filter(p => p.done).length
    if (!confirm(`Unpin ${n} done item${n === 1 ? '' : 's'} from Focus? (The reminders/list items themselves stay.)`)) return
    await fetch('/api/focus?done=1', { method: 'DELETE' })
    load()
  }

  // Shareable plain-text snapshot: tasks by list, then each pinned whole list.
  const copyAsText = async () => {
    const openLeft = tasks.filter(p => !p.done).length
    const out: string[] = [`Focus — ${openLeft} left`]
    const byGroup = new Map<string, TaskPin[]>()
    for (const p of tasks) { const k = p.list || NO_LIST; if (!byGroup.has(k)) byGroup.set(k, []); byGroup.get(k)!.push(p) }
    for (const k of [...byGroup.keys()].sort()) {
      out.push('', `— ${k} —`)
      for (const p of byGroup.get(k)!) out.push(`${p.done ? '✅' : '⬜'} ${p.title}`)
    }
    for (const l of lists) {
      out.push('', `— ${l.name} —`)
      for (const i of l.items) out.push(`${i.done ? '✅' : '⬜'} ${i.title}`)
    }
    try {
      await navigator.clipboard.writeText(out.join('\n'))
      setCopied(true)
      setTimeout(() => setCopied(false), 2000)
    } catch { /* clipboard unavailable */ }
  }

  // Group tasks by AI topic (default) or by their list. Ungrouped tasks fall
  // into "Other" / "Reminders", which sort last via the sentinel prefix.
  const doneCount = tasks.filter(p => p.done).length
  const shownTasks = showDone ? tasks : tasks.filter(p => !p.done || recentlyDone.has(p.pinId))
  // The household board sits above your own. A shared pin is deliberately NOT
  // also grouped by topic below — it would read as two copies of one task.
  const sharedTasks = shownTasks.filter(p => p.shared)
  const personalTasks = shownTasks.filter(p => !p.shared)
  const keyOf = (p: TaskPin) => groupBy === 'topic' ? (p.topic || `${SENT}${OTHER}`) : (p.list || `${SENT}${NO_LIST}`)
  const groups = new Map<string, TaskPin[]>()
  for (const p of personalTasks) {
    const key = keyOf(p)
    if (!groups.has(key)) groups.set(key, [])
    groups.get(key)!.push(p)
  }
  const orderedKeys = [...groups.keys()].sort()
  const anyDone = doneCount > 0
  const openLeft = tasks.filter(p => !p.done).length
  const empty = pins.length === 0

  // Moving a pin to the household board also shares the record behind it (the
  // server does that, and refuses if you don't own it) — so the family can
  // actually open what they see.
  const setShared = async (p: TaskPin | ListPin, shared: boolean) => {
    setPins(prev => prev.map(x => x.pinId === p.pinId ? { ...x, shared } : x))
    const res = await fetch(`/api/focus/${p.pinId}`, {
      method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ shared }),
    })
    if (!res.ok) { setPins(prev => prev.map(x => x.pinId === p.pinId ? { ...x, shared: !shared } : x)); load() }
  }

  const shareButton = (p: TaskPin | ListPin) => p.mine ? (
    <button onClick={() => setShared(p, !p.shared)} className={`shrink-0 mt-0.5 ${p.shared ? 'text-primary' : 'text-muted-foreground hover:text-foreground'}`}
      aria-label={p.shared ? 'Move off the shared board' : 'Share with the household'}
      title={p.shared ? 'Shared with the household — tap to remove it from the shared board' : 'Share with the household (they will be able to open this item)'}>
      {p.shared ? <Users className="h-4 w-4" /> : <Lock className="h-4 w-4" />}
    </button>
  ) : null

  const taskRow = (p: TaskPin) => (
    <li key={p.pinId} className="rounded-xl border border-border bg-card px-3 py-2">
      <div className={`flex gap-2 text-sm ${editing === p.pinId ? 'items-center' : 'items-start'}`}>
        <button onClick={() => toggleTask(p)} className={p.done ? 'text-emerald-600' : 'text-muted-foreground hover:text-primary'} aria-label="Toggle done">
          {p.done ? <CheckCircle2 className="h-5 w-5" /> : <Circle className="h-5 w-5" />}
        </button>
        {editing === p.pinId ? (
          <>
            <input
              autoFocus
              value={editText}
              onChange={e => setEditText(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter') saveEdit(p); if (e.key === 'Escape') setEditing(null) }}
              onBlur={() => saveEdit(p)}
              className="min-w-0 flex-1 rounded-md border border-input bg-background px-2 h-8 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
            />
            <button onMouseDown={e => { e.preventDefault(); saveEdit(p) }} className="text-primary shrink-0" aria-label="Save"><Check className="h-4 w-4" /></button>
          </>
        ) : (
          <>
            <span onClick={() => { if (!window.getSelection()?.toString()) startEdit(p) }}
              className={`min-w-0 flex-1 inline-flex items-start gap-1.5 cursor-text ${p.done ? 'line-through text-muted-foreground' : ''}`}>
              {p.kind === 'item' && <ClipboardList className="h-3.5 w-3.5 mt-[3px] shrink-0 text-muted-foreground" />}
              <span className="min-w-0 break-words">{p.title}</span>
            </span>
            {shareButton(p)}
            {p.kind === 'reminder' && (
              <button onClick={() => pickFor(p.id)} className="text-muted-foreground hover:text-foreground shrink-0 mt-0.5" aria-label="Attach file" title="Attach an image or file"><Paperclip className="h-4 w-4" /></button>
            )}
            <button onClick={() => unpin(p.pinId)} className="text-muted-foreground hover:text-destructive shrink-0 mt-0.5" aria-label="Unpin from Focus" title="Remove from Focus (the original stays)"><X className="h-4 w-4" /></button>
          </>
        )}
      </div>
      {p.kind === 'reminder' && <AttachmentRow atts={p.attachments || []} onDelete={id => delAtt(p.id, id)} className="mt-1.5 pl-7" />}
    </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 inline-flex items-center gap-1.5 mr-2"><Target className="h-4 w-4 text-primary" /> Focus</span>
        <button onClick={copyAsText} className="inline-flex items-center gap-1.5 text-sm rounded-lg border border-border px-2.5 h-8 hover:bg-muted" title="Copy as text">
          {copied ? <><Check className="h-4 w-4 text-emerald-600" /> Copied</> : <><Copy className="h-4 w-4" /> Copy</>}
        </button>
        <button onClick={organize} disabled={organizing} className="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="Re-group by topic with AI">
          <Sparkles className={`h-4 w-4 ${organizing ? 'animate-pulse' : ''}`} /> {organizing ? 'Organizing…' : 'Organize'}
        </button>
      </header>

      <main className="flex-1 px-4 pb-10 space-y-3">
        <input ref={fileInputRef} type="file" multiple onChange={onPickFiles} className="hidden" />
        <div className="flex gap-2">
          <input
            value={draft}
            onChange={e => setDraft(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter') add() }}
            placeholder="Add to focus…"
            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"
          />
          <button onClick={add} className="rounded-lg bg-primary text-primary-foreground px-3 h-10 inline-flex items-center" aria-label="Add"><Plus className="h-4 w-4" /></button>
        </div>

        <div className="flex items-center gap-3 px-1">
          <span className="text-xs rounded-full bg-card border border-border px-2 py-0.5 text-muted-foreground">{openLeft} left</span>
          {tasks.length > 0 && (
            <div className="inline-flex rounded-full border border-border overflow-hidden text-xs">
              <button onClick={() => setGroupBy('topic')} className={`px-2 py-0.5 ${groupBy === 'topic' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}>Topic</button>
              <button onClick={() => setGroupBy('list')} className={`px-2 py-0.5 ${groupBy === 'list' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted'}`}>List</button>
            </div>
          )}
          {anyDone && (
            <button onClick={() => setShowDone(s => !s)} className="inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground">
              {showDone ? <><EyeOff className="h-3.5 w-3.5" /> Hide done</> : <><Eye className="h-3.5 w-3.5" /> Show done ({doneCount})</>}
            </button>
          )}
          {anyDone && (
            <button onClick={clearDone} className="ml-auto text-xs text-muted-foreground hover:text-foreground">Clear done</button>
          )}
        </div>

        {loaded && empty && <p className="text-sm text-muted-foreground text-center py-6">Nothing in focus — add something above, or drag a reminder, list item, or whole list here.</p>}

        {/* The household board, above your own. */}
        {sharedTasks.length > 0 && (
          <section className="space-y-2">
            <div className="px-1 pt-1 text-sm font-semibold flex items-center gap-2">
              <Users className="h-4 w-4 text-primary" />
              Shared with the household
              <span className="text-xs rounded-full bg-muted px-2 py-0.5 text-muted-foreground font-normal">
                {showDone ? `${sharedTasks.filter(p => !p.done).length}/${sharedTasks.length}` : sharedTasks.length}
              </span>
            </div>
            <ul className="space-y-1.5">{sharedTasks.map(taskRow)}</ul>
          </section>
        )}

        {/* Your own pins, grouped by topic or list. */}
        {orderedKeys.map(key => {
          const label = key.startsWith(SENT) ? key.slice(SENT.length) : key
          const list = groups.get(key)!
          return (
            <section key={key} className="space-y-2">
              <div className="px-1 pt-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">
                  {showDone ? `${list.filter(p => !p.done).length}/${list.length}` : list.length}
                </span>
              </div>
              <ul className="space-y-1.5">{list.map(taskRow)}</ul>
            </section>
          )
        })}

        {/* Pinned whole lists, each expanded inline. */}
        {lists.map(l => {
          const sorted = [...l.items].sort((a, b) => Number(a.done) - Number(b.done) || Number(a.optional) - Number(b.optional))
          const doneN = l.items.filter(i => i.done).length
          return (
            <section key={l.pinId} className="space-y-2">
              <div className="px-1 pt-1 text-sm font-semibold flex items-center gap-2">
                <ClipboardList className="h-4 w-4 text-primary" />
                <Link href={`/list/${l.id}`} className="hover:underline">{l.name}</Link>
                <span className="text-xs rounded-full bg-muted px-2 py-0.5 text-muted-foreground font-normal">{doneN}/{l.items.length}</span>
                <span className="ml-auto flex items-center gap-2">
                  {shareButton(l)}
                  <button onClick={() => unpin(l.pinId)} className="text-muted-foreground hover:text-destructive" aria-label="Unpin list from Focus" title="Remove from Focus (the list stays)"><X className="h-4 w-4" /></button>
                </span>
              </div>
              {sorted.length === 0 ? (
                <p className="px-1 text-xs text-muted-foreground">Empty list.</p>
              ) : (
                <ul className="space-y-1.5">
                  {sorted.map(i => (
                    <li key={i.id} className="rounded-xl border border-border bg-card px-3 py-2">
                      <div className="flex items-start gap-2 text-sm">
                        <button onClick={() => toggleListItem(l.id, i)} className={i.done ? 'text-emerald-600' : 'text-muted-foreground hover:text-primary'} aria-label="Toggle done">
                          {i.done ? <CheckCircle2 className="h-5 w-5" /> : <Circle className="h-5 w-5" />}
                        </button>
                        <span className={`min-w-0 flex-1 break-words ${i.done ? 'line-through text-muted-foreground' : ''} ${i.optional && !i.done ? 'text-muted-foreground' : ''}`}>{i.title}</span>
                      </div>
                    </li>
                  ))}
                </ul>
              )}
            </section>
          )
        })}
      </main>
    </div>
  )
}
