'use client'

import { useCallback, useEffect, useMemo, useState } from 'react'
import { ArrowLeft, GitMerge, Loader2, Pencil, Plus, Trash2, X } from 'lucide-react'
import { toast } from 'sonner'
import {
  createPageTag,
  deletePageTagWithDetach,
  fetchPages,
  mergePageTags,
  updatePageTag,
  type PageTag,
} from '../../lib/pages-service.js'
import { PageTagPill, tagDotColor } from '../../components/pages/tag-badges.js'
import { ConfirmDialog } from '../../components/ui/ConfirmDialog.js'

const TAG_COLORS = ['purple', 'green', 'orange', 'red', 'blue', 'pink', 'gray'] as const

export interface PageTagManagerProps {
  onNavigate: (path: string) => void
  /** When set, the create form opens pre-expanded (route /pages/tags/new). */
  startCreating?: boolean
}

/**
 * /pages/tags — create, rename, recolor, merge, and delete page tags.
 *
 * Tags are documents in the hidden `page-tags` collection; pages
 * reference them by slug in `data.tags`. Deleting a tag detaches it
 * from every page first so no dangling slugs remain.
 */
export function PageTagManager({ onNavigate, startCreating = false }: PageTagManagerProps) {
  const [tags, setTags] = useState<PageTag[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [refreshToken, setRefreshToken] = useState(0)

  const [creating, setCreating] = useState(startCreating)
  const [pendingDelete, setPendingDelete] = useState<PageTag | null>(null)

  const existingSlugs = useMemo(() => new Set(tags.map((t) => t.slug)), [tags])

  const load = useCallback(async () => {
    setLoading(true)
    setError(null)
    try {
      // fetchPages returns tags with accurate page counts.
      const res = await fetchPages({ pageSize: 1 })
      setTags(res.tags)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to load tags')
    } finally {
      setLoading(false)
    }
  }, [])

  useEffect(() => {
    void load()
  }, [load, refreshToken])

  const refresh = () => setRefreshToken((t) => t + 1)

  const handleDelete = async (tag: PageTag) => {
    const promise = deletePageTagWithDetach(tag)
    toast.promise(promise, {
      loading: `Deleting "${tag.name}"…`,
      success: () => `Deleted "${tag.name}"`,
      error: 'Failed to delete tag',
    })
    await promise
    setPendingDelete(null)
    refresh()
  }

  return (
    <div className="p-4 pr-8 sm:p-6">
      <button
        type="button"
        onClick={() => onNavigate('/pages')}
        className="text-muted-foreground hover:text-foreground mb-4 inline-flex items-center gap-1.5 text-sm"
      >
        <ArrowLeft className="h-4 w-4" aria-hidden />
        Back to Pages
      </button>

      <div className="mb-5 flex items-center justify-between">
        <div>
          <h1 className="text-foreground mb-1 text-xl font-medium tracking-tight sm:text-2xl">
            Page Tags
          </h1>
          <p className="text-muted-foreground text-sm">
            Organize pages with reusable, color-coded labels.
          </p>
        </div>
        {!creating && (
          <button
            type="button"
            onClick={() => setCreating(true)}
            className="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center gap-1.5 rounded-lg px-3.5 py-1.5 text-sm font-medium shadow-sm transition-colors"
          >
            <Plus className="h-3.5 w-3.5" aria-hidden />
            New tag
          </button>
        )}
      </div>

      {creating && (
        <CreateTagForm
          existingSlugs={existingSlugs}
          onCancel={() => setCreating(false)}
          onCreated={() => {
            setCreating(false)
            refresh()
          }}
        />
      )}

      {loading ? (
        <div className="flex h-48 items-center justify-center" role="status" aria-live="polite">
          <Loader2 className="text-primary h-6 w-6 animate-spin" aria-hidden />
          <span className="sr-only">Loading tags</span>
        </div>
      ) : error ? (
        <div className="border-border bg-card flex items-center gap-3 rounded-lg border p-3">
          <span className="text-foreground flex-1 text-sm">{error}</span>
          <button
            type="button"
            onClick={refresh}
            className="border-border text-foreground hover:bg-accent rounded-md border px-3 py-1 text-sm"
          >
            Retry
          </button>
        </div>
      ) : tags.length === 0 ? (
        <div className="border-border bg-card rounded-lg border p-8 text-center">
          <h2 className="text-foreground mb-1 text-lg font-medium">No tags yet</h2>
          <p className="text-muted-foreground text-sm">Create a tag to start organizing pages.</p>
        </div>
      ) : (
        <div className="bg-card border-border divide-border divide-y overflow-hidden rounded-xl border shadow-sm">
          {tags.map((tag) => (
            <TagRow
              key={tag.docId}
              tag={tag}
              allTags={tags}
              onChanged={refresh}
              onRequestDelete={() => setPendingDelete(tag)}
            />
          ))}
        </div>
      )}

      <ConfirmDialog
        open={pendingDelete !== null}
        title={`Delete "${pendingDelete?.name ?? ''}"?`}
        description={
          pendingDelete && pendingDelete.pageCount > 0
            ? `This tag is used on ${pendingDelete.pageCount} page${
                pendingDelete.pageCount === 1 ? '' : 's'
              }. It will be removed from those pages. This cannot be undone.`
            : 'This tag has no pages. Deleting it cannot be undone.'
        }
        confirmLabel="Delete tag"
        destructive
        onClose={() => setPendingDelete(null)}
        onConfirm={() => {
          if (pendingDelete) void handleDelete(pendingDelete)
        }}
      />
    </div>
  )
}

// ─── Create form ─────────────────────────────────────────────────────

function CreateTagForm({
  existingSlugs,
  onCancel,
  onCreated,
}: {
  existingSlugs: Set<string>
  onCancel: () => void
  onCreated: () => void
}) {
  const [name, setName] = useState('')
  const [color, setColor] = useState<string>('purple')
  const [submitting, setSubmitting] = useState(false)

  const slug = name
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
  const duplicate = slug.length > 0 && existingSlugs.has(slug)
  const canSubmit = slug.length > 0 && !duplicate && !submitting

  const submit = async () => {
    if (!canSubmit) return
    setSubmitting(true)
    const res = await createPageTag({ name: name.trim(), color })
    setSubmitting(false)
    if (res.error) {
      toast.error(res.error)
      return
    }
    toast.success(`Created "${name.trim()}"`)
    onCreated()
  }

  return (
    <div className="border-border bg-card mb-5 rounded-xl border p-4 shadow-sm">
      <div className="flex flex-wrap items-end gap-3">
        <label className="flex-1">
          <span className="text-foreground mb-1 block text-sm font-medium">Tag name</span>
          <input
            type="text"
            value={name}
            autoFocus
            onChange={(e) => setName(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === 'Enter') void submit()
            }}
            placeholder="e.g. Marketing"
            className="border-border bg-input-background text-foreground focus:border-primary focus:ring-primary/30 w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
          />
        </label>
        <ColorPicker value={color} onChange={setColor} />
        <button
          type="button"
          onClick={() => void submit()}
          disabled={!canSubmit}
          className="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-medium shadow-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50"
        >
          {submitting ? <Loader2 className="h-4 w-4 animate-spin" aria-hidden /> : null}
          Create
        </button>
        <button
          type="button"
          onClick={onCancel}
          className="text-muted-foreground hover:text-foreground inline-flex items-center gap-1 px-2 py-2 text-sm"
        >
          <X className="h-4 w-4" aria-hidden />
          Cancel
        </button>
      </div>
      {duplicate && (
        <p className="text-destructive mt-2 text-xs">A tag with that name already exists.</p>
      )}
    </div>
  )
}

function ColorPicker({ value, onChange }: { value: string; onChange: (c: string) => void }) {
  return (
    <div>
      <span className="text-foreground mb-1 block text-sm font-medium">Color</span>
      <div className="flex items-center gap-1.5" role="radiogroup" aria-label="Tag color">
        {TAG_COLORS.map((c) => (
          <button
            key={c}
            type="button"
            role="radio"
            aria-checked={value === c}
            aria-label={c}
            onClick={() => onChange(c)}
            className={`h-7 w-7 rounded-full ${tagDotColor(c)} ring-offset-background transition-shadow ${
              value === c ? 'ring-ring ring-2 ring-offset-2' : ''
            }`}
          />
        ))}
      </div>
    </div>
  )
}

// ─── Tag row ─────────────────────────────────────────────────────────

function TagRow({
  tag,
  allTags,
  onChanged,
  onRequestDelete,
}: {
  tag: PageTag
  allTags: PageTag[]
  onChanged: () => void
  onRequestDelete: () => void
}) {
  const [editing, setEditing] = useState(false)
  const [name, setName] = useState(tag.name)
  const [color, setColor] = useState(tag.color ?? 'gray')
  const [merging, setMerging] = useState(false)

  const save = async () => {
    const res = await updatePageTag(tag.docId, { name: name.trim(), color })
    if (res.error) {
      toast.error(res.error)
      return
    }
    toast.success('Tag updated')
    setEditing(false)
    onChanged()
  }

  const merge = async (targetSlug: string) => {
    const target = allTags.find((t) => t.slug === targetSlug)
    if (!target) return
    const promise = mergePageTags(tag, target)
    toast.promise(promise, {
      loading: `Merging "${tag.name}" into "${target.name}"…`,
      success: () => `Merged into "${target.name}"`,
      error: 'Merge failed',
    })
    await promise
    setMerging(false)
    onChanged()
  }

  if (editing) {
    return (
      <div className="flex flex-wrap items-end gap-3 p-4">
        <label className="flex-1">
          <span className="sr-only">Tag name</span>
          <input
            type="text"
            value={name}
            onChange={(e) => setName(e.target.value)}
            className="border-border bg-input-background text-foreground focus:border-primary focus:ring-primary/30 w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none"
          />
        </label>
        <ColorPicker value={color} onChange={setColor} />
        <button
          type="button"
          onClick={() => void save()}
          className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg px-3.5 py-2 text-sm font-medium"
        >
          Save
        </button>
        <button
          type="button"
          onClick={() => {
            setEditing(false)
            setName(tag.name)
            setColor(tag.color ?? 'gray')
          }}
          className="text-muted-foreground hover:text-foreground px-2 py-2 text-sm"
        >
          Cancel
        </button>
      </div>
    )
  }

  return (
    <div className="flex items-center gap-3 p-4">
      <div className="flex min-w-0 flex-1 items-center gap-3">
        <PageTagPill name={tag.name} color={tag.color} />
        <span className="text-muted-foreground text-sm tabular-nums">
          {tag.pageCount} page{tag.pageCount === 1 ? '' : 's'}
        </span>
      </div>

      {merging ? (
        <div className="flex items-center gap-2">
          <label className="text-foreground inline-flex items-center gap-1.5 text-sm">
            <span className="text-muted-foreground">Merge into:</span>
            <select
              defaultValue=""
              onChange={(e) => {
                if (e.target.value) void merge(e.target.value)
              }}
              className="border-border bg-card text-foreground rounded-lg border px-2.5 py-1.5 text-sm"
            >
              <option value="" disabled>
                Choose tag…
              </option>
              {allTags
                .filter((t) => t.slug !== tag.slug)
                .map((t) => (
                  <option key={t.slug} value={t.slug}>
                    {t.name}
                  </option>
                ))}
            </select>
          </label>
          <button
            type="button"
            onClick={() => setMerging(false)}
            className="text-muted-foreground hover:text-foreground px-2 py-1 text-sm"
          >
            Cancel
          </button>
        </div>
      ) : (
        <div className="flex items-center gap-1">
          <IconAction label={`Edit ${tag.name}`} onClick={() => setEditing(true)}>
            <Pencil className="h-4 w-4" aria-hidden />
          </IconAction>
          {allTags.length > 1 && (
            <IconAction label={`Merge ${tag.name}`} onClick={() => setMerging(true)}>
              <GitMerge className="h-4 w-4" aria-hidden />
            </IconAction>
          )}
          <IconAction label={`Delete ${tag.name}`} onClick={onRequestDelete} destructive>
            <Trash2 className="h-4 w-4" aria-hidden />
          </IconAction>
        </div>
      )}
    </div>
  )
}

function IconAction({
  label,
  onClick,
  destructive,
  children,
}: {
  label: string
  onClick: () => void
  destructive?: boolean
  children: React.ReactNode
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      aria-label={label}
      className={`hover:bg-accent inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors ${
        destructive ? 'text-destructive hover:bg-destructive/10' : 'text-muted-foreground'
      }`}
    >
      {children}
    </button>
  )
}
