'use client'

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

interface Item { id: string; title: string; done: boolean; optional: boolean; topic: string | null; attachments: Att[] }
interface ListData { id: string; name: string; dismissed: boolean; visibility: 'PRIVATE' | 'HOUSEHOLD'; mine: boolean; items: Item[] }

// One special list: add/check/edit items, rename the list, dismiss when done.
// Done items stay visible (struck through) — on a packing list you want to
// see what's already handled.
export function ChecklistPage({ listId }: { listId: string }) {
  const router = useRouter()
  const [list, setList] = useState<ListData | null>(null)
  const [loaded, setLoaded] = useState(false)
  const [draft, setDraft] = useState('')
  const [editing, setEditing] = useState<string | null>(null)
  const [editText, setEditText] = useState('')
  const [renaming, setRenaming] = useState(false)
  const [copied, setCopied] = useState(false)
  const [grouped, setGrouped] = useState(false)
  const [organizing, setOrganizing] = useState(false)
  const [nameDraft, setNameDraft] = useState('')
  // Files attached to the NEW item before it exists (staged, uploaded on add).
  const [staged, setStaged] = useState<{ file: File; url: string }[]>([])
  const attachTargetRef = useRef<string | null>(null)
  const fileInputRef = useRef<HTMLInputElement>(null)
  const newFileInputRef = useRef<HTMLInputElement>(null)
  const pickFor = (id: string) => { attachTargetRef.current = id; fileInputRef.current?.click() }
  const uploadToItem = async (id: string, files: File[]) => {
    const atts = await uploadAttachments('checklist', id, files)
    if (atts.length > 0) setList(l => l && ({ ...l, items: l.items.map(i => i.id === id ? { ...i, attachments: [...(i.attachments || []), ...atts] } : i) }))
  }
  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
    await uploadToItem(target, files)
  }
  const delAtt = async (itemId: string, attId: string) => {
    setList(l => l && ({ ...l, items: l.items.map(i => i.id === itemId ? { ...i, attachments: (i.attachments || []).filter(a => a.id !== attId) } : i) }))
    await deleteAttachment(attId)
  }
  // ── attach to a not-yet-created item: stage now, upload after add ──────────
  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))
  }
  const onPickNew = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || [])
    e.target.value = ''
    stageFiles(files)
  }
  // Paste an image anywhere on the page: into the row being edited if one is
  // open, otherwise stage it for the new item.
  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) uploadToItem(editing, files)
      else stageFiles(files)
    }
    document.addEventListener('paste', onPaste)
    return () => document.removeEventListener('paste', onPaste)
  })

  const load = useCallback(async () => {
    const res = await fetch(`/api/checklists/${listId}`, { cache: 'no-store' })
    if (res.ok) setList(await res.json())
    setLoaded(true)
  }, [listId])
  useEffect(() => {
    load()
    // Categories arrive asynchronously (auto-organize after adds) — poll
    // lightly so new items slide out of "Other" without a manual reload.
    const t = setInterval(load, 15000)
    return () => clearInterval(t)
  }, [load])

  const add = async () => {
    // Allow an image-only add (no typed title) by falling back to the filename.
    const title = draft.trim() || staged[0]?.file.name.replace(/\.[^.]+$/, '') || ''
    if (!title) return
    setDraft('')
    const res = await fetch(`/api/checklists/${listId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title }) })
    if (res.ok && staged.length > 0) {
      const { id } = await res.json()
      await uploadAttachments('checklist', id, staged.map(x => x.file))
      staged.forEach(x => URL.revokeObjectURL(x.url))
      setStaged([])
    }
    load()
  }
  const toggle = async (i: Item) => {
    setList(l => l && ({ ...l, items: l.items.map(x => x.id === i.id ? { ...x, done: !i.done } : x) }))
    await fetch(`/api/checklist-items/${i.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ done: !i.done }) })
  }
  const toggleOptional = async (i: Item) => {
    setList(l => l && ({ ...l, items: l.items.map(x => x.id === i.id ? { ...x, optional: !i.optional } : x) }))
    await fetch(`/api/checklist-items/${i.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ optional: !i.optional }) })
  }
  const removeItem = async (id: string) => {
    setList(l => l && ({ ...l, items: l.items.filter(x => x.id !== id) }))
    await fetch(`/api/checklist-items/${id}`, { method: 'DELETE' })
  }
  const saveEdit = async (id: string) => {
    const title = editText.trim()
    setEditing(null)
    if (!title) return
    setList(l => l && ({ ...l, items: l.items.map(x => x.id === id ? { ...x, title } : x) }))
    await fetch(`/api/checklist-items/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title }) })
  }
  const saveName = async () => {
    const name = nameDraft.trim()
    setRenaming(false)
    if (!name || !list) return
    setList({ ...list, name })
    await fetch(`/api/checklists/${listId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name }) })
  }
  // Only the owner may change who can see a list — everyone else just gets
  // the badge. Optimistic, like the rename above it.
  const toggleShared = async () => {
    if (!list) return
    const visibility = list.visibility === 'HOUSEHOLD' ? 'PRIVATE' : 'HOUSEHOLD'
    setList({ ...list, visibility })
    await fetch(`/api/checklists/${listId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ visibility }) })
  }
  const dismiss = async () => {
    if (!list) return
    if (!confirm(`Dismiss “${list.name}”? The list disappears from the dashboard (it's kept in the database, not deleted).`)) return
    await fetch(`/api/checklists/${listId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ dismissed: true }) })
    router.push('/')
  }

  const doneCount = list?.items.filter(i => i.done).length ?? 0
  // Checked items sink to the bottom (stable: keeps added order within groups).
  const sortedItems = list ? [...list.items].sort((a, b) => Number(a.done) - Number(b.done) || Number(a.optional) - Number(b.optional)) : []

  // AI-grouped view: sections by item.topic (assigned by the organize pass).
  const sections: { topic: string | null; items: Item[] }[] = (() => {
    if (!grouped) return [{ topic: null, items: sortedItems }]
    const m = new Map<string, Item[]>()
    for (const i of sortedItems) {
      const key = i.topic || '\uffffOther'
      if (!m.has(key)) m.set(key, [])
      m.get(key)!.push(i)
    }
    return [...m.keys()].sort().map(k => ({ topic: k === '\uffffOther' ? 'Other' : k, items: m.get(k)! }))
  })()

  // Re-run the AI categorization on demand (Claude on the Mac); show groups
  // and reload once it's had time to run.
  const organize = async () => {
    setOrganizing(true)
    setGrouped(true)
    await fetch('/api/organize', { method: 'POST' }).catch(() => {})
    setTimeout(load, 20000)
    setTimeout(() => { load(); setOrganizing(false) }, 40000)
  }
  const toggleGrouped = async () => {
    const next = !grouped
    setGrouped(next)
    // First time on an uncategorized list: kick the organize pass.
    if (next && list && list.items.length > 0 && list.items.every(i => !i.topic)) organize()
  }

  // Shareable plain-text snapshot (paste into iMessage/email so others can
  // see progress or grab a copy of the list).
  const copyAsText = async () => {
    if (!list) return
    const lines: string[] = [`${list.name} — ${doneCount}/${list.items.length} done`]
    for (const sec of sections) {
      if (grouped && sec.topic) lines.push('', `— ${sec.topic} —`)
      for (const i of sec.items) lines.push(`${i.done ? '✅' : '⬜'} ${i.title}${i.optional ? ' (optional)' : ''}`)
    }
    const text = lines.join('\n')
    try {
      await navigator.clipboard.writeText(text)
      setCopied(true)
      setTimeout(() => setCopied(false), 2000)
    } catch { /* clipboard unavailable */ }
  }

  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">
          <ClipboardList className="h-4 w-4 text-primary" />
          {renaming ? (
            <input
              autoFocus
              value={nameDraft}
              onChange={e => setNameDraft(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter') saveName(); if (e.key === 'Escape') setRenaming(false) }}
              onBlur={saveName}
              className="rounded-md border border-input bg-background px-2 h-8 text-sm w-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
            />
          ) : (
            <button onClick={() => { if (list) { setRenaming(true); setNameDraft(list.name) } }} className="hover:opacity-80" title="Rename list">
              {list?.name ?? 'List'}
            </button>
          )}
        </span>
      </header>

      <main className="flex-1 px-4 pb-10 space-y-3">
        <input ref={fileInputRef} type="file" multiple onChange={onPickFiles} className="hidden" />
        <input ref={newFileInputRef} type="file" multiple onChange={onPickNew} 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 item…"
            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={() => newFileInputRef.current?.click()} className="rounded-lg border border-border px-3 h-10 inline-flex items-center text-muted-foreground hover:bg-muted" aria-label="Attach image or file to new item" title="Attach an image or file (or just paste)"><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"><Plus className="h-4 w-4" /></button>
        </div>
        {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>
        )}

        {list && list.items.length > 0 && (
          <div className="px-1 text-xs text-muted-foreground flex items-center gap-3">
            <span>{doneCount}/{list.items.length} done</span>
            <button onClick={toggleGrouped} className={`inline-flex items-center gap-1 hover:text-foreground ${grouped ? 'text-primary' : ''}`}>
              <Layers className="h-3.5 w-3.5" />
              {grouped ? 'AI groups on' : 'Group with AI'}
            </button>
            <button onClick={organize} disabled={organizing} className="ml-auto inline-flex items-center gap-1 hover:text-foreground disabled:opacity-50">
              <Sparkles className={`h-3.5 w-3.5 ${organizing ? 'animate-pulse' : ''}`} />
              {organizing ? 'Organizing…' : 'Organize'}
            </button>
          </div>
        )}

        {loaded && !list && <p className="text-sm text-muted-foreground text-center py-10">List not found.</p>}
        {loaded && list && list.items.length === 0 && <p className="text-sm text-muted-foreground text-center py-6">Empty list — add what you need above.</p>}

        {sections.map(sec => (
        <section key={sec.topic ?? 'flat'} className="space-y-1.5">
          {grouped && sec.topic && (
            <div className="px-1 pt-1 text-sm font-semibold flex items-center gap-2">
              {sec.topic}
              <span className="text-xs rounded-full bg-muted px-2 py-0.5 text-muted-foreground font-normal">{sec.items.filter(i => !i.done).length}/{sec.items.length}</span>
            </div>
          )}
        <ul className="space-y-1.5">
          {sec.items.map(i => (
            <li key={i.id} className="rounded-xl border border-border bg-card px-3 py-2">
            <div className="flex items-center gap-2 text-sm">
              <button onClick={() => toggle(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>
              {editing === i.id ? (
                <>
                  <input
                    autoFocus
                    value={editText}
                    onChange={e => setEditText(e.target.value)}
                    onKeyDown={e => { if (e.key === 'Enter') saveEdit(i.id); if (e.key === 'Escape') setEditing(null) }}
                    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 onClick={() => saveEdit(i.id)} className="text-primary shrink-0" aria-label="Save"><Check className="h-4 w-4" /></button>
                  <button onClick={() => setEditing(null)} className="text-muted-foreground hover:text-foreground shrink-0" aria-label="Cancel"><X className="h-4 w-4" /></button>
                </>
              ) : (
                <>
                  <span
                    onClick={() => { if (!window.getSelection()?.toString()) { setEditing(i.id); setEditText(i.title) } }}
                    className={`min-w-0 flex-1 cursor-pointer ${i.done ? 'line-through text-muted-foreground' : i.optional ? 'text-muted-foreground' : ''}`}
                  >
                    {i.title}
                    {i.optional && <span className="ml-1.5 text-[10px] uppercase tracking-wide rounded-full bg-muted px-1.5 py-0.5 text-muted-foreground align-middle">optional</span>}
                  </span>
                  <button onClick={() => toggleOptional(i)} className={`shrink-0 ${i.optional ? 'text-amber-500' : 'text-muted-foreground hover:text-foreground'}`} aria-label="Toggle optional" title="Optional — not sure we need it"><HelpCircle className="h-4 w-4" /></button>
                  <button onClick={() => pickFor(i.id)} className="text-muted-foreground hover:text-foreground shrink-0" aria-label="Attach file" title="Attach an image or file"><Paperclip className="h-4 w-4" /></button>
                  <button onClick={() => removeItem(i.id)} className="text-muted-foreground hover:text-destructive shrink-0" aria-label="Remove"><X className="h-4 w-4" /></button>
                </>
              )}
            </div>
            <AttachmentRow atts={i.attachments || []} onDelete={id => delAtt(i.id, id)} className="mt-1.5 pl-7" />
            </li>
          ))}
        </ul>
        </section>
        ))}

        {list && (
          <div className="pt-4 space-y-2">
            <button onClick={copyAsText} className="w-full inline-flex items-center justify-center gap-1.5 text-sm rounded-xl border border-border py-2.5 text-muted-foreground hover:text-foreground hover:bg-muted">
              {copied ? <><Check className="h-4 w-4 text-emerald-600" /> Copied</> : <><Copy className="h-4 w-4" /> Copy as text</>}
            </button>
            {list.mine && (
              <button onClick={toggleShared} className="w-full inline-flex items-center justify-center gap-1.5 text-sm rounded-xl border border-border py-2.5 text-muted-foreground hover:text-foreground hover:bg-muted">
                {list.visibility === 'HOUSEHOLD'
                  ? <><Users className="h-4 w-4 text-primary" /> Shared with the household — make private</>
                  : <><Lock className="h-4 w-4" /> Private — share with the household</>}
              </button>
            )}
            <button onClick={dismiss} className="w-full inline-flex items-center justify-center gap-1.5 text-sm rounded-xl border border-border py-2.5 text-muted-foreground hover:text-foreground hover:bg-muted">
              <Archive className="h-4 w-4" /> Dismiss list
            </button>
          </div>
        )}
      </main>
    </div>
  )
}
