'use client'

import { useEffect, useMemo, useState } from 'react'
import {
  Check,
  ChevronRight,
  Copy,
  ExternalLink,
  FileQuestion,
  LayoutTemplate,
  Lock,
  Plus,
} from 'lucide-react'
import { toast } from 'sonner'
import { fetchPosts } from '../../lib/posts-service.js'
import {
  fetchPostTypeDetail,
  fieldKeyFromName,
  fieldTypeLabel,
  humanizeFieldName,
  renderFieldSnippet,
  type PostTypeDetail,
} from '../../lib/post-types-service.js'
import { paletteFor } from '../../components/posts/badges.js'
import { resolvePostTypeIcon } from '../../components/posts/icons.js'
import { Toggle } from '../../components/ui/Toggle.js'

/**
 * /posts/types/:slug/edit — Post Type editor (design `TypeEditor`).
 *
 * Layout matches the design split: toolbar, 340px identity panel, field
 * builder. Collections are file-defined in `actuate.config.ts`, so identity
 * and the field list are the *live schema* rendered read-only, and "Add
 * Field" emits a paste-ready config snippet instead of mutating a schema
 * the server can't persist (same model as the New Post Type flow).
 */

interface PostTypeEditorProps {
  slug: string
  onNavigate: (path: string) => void
}

const ADDABLE_FIELD_TYPES: { type: string; desc: string }[] = [
  { type: 'text', desc: 'Single line' },
  { type: 'richText', desc: 'WYSIWYG' },
  { type: 'number', desc: 'Int / decimal' },
  { type: 'date', desc: 'Date & time' },
  { type: 'boolean', desc: 'True / false' },
  { type: 'url', desc: 'Web address' },
  { type: 'email', desc: 'Email address' },
  { type: 'select', desc: 'Dropdown' },
  { type: 'media', desc: 'Image / file' },
  { type: 'relationship', desc: 'Link to type' },
  { type: 'json', desc: 'Raw data' },
]

export function PostTypeEditor({ slug, onNavigate }: PostTypeEditorProps) {
  const [detail, setDetail] = useState<PostTypeDetail | null>(null)
  const [postCount, setPostCount] = useState<number | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [notFound, setNotFound] = useState(false)
  const [refreshToken, setRefreshToken] = useState(0)

  useEffect(() => {
    let cancelled = false
    setLoading(true)
    setError(null)
    setNotFound(false)
    Promise.all([fetchPostTypeDetail(slug), fetchPosts({ pageSize: 1 }).catch(() => null)])
      .then(([d, postsRes]) => {
        if (cancelled) return
        if (!d) {
          setNotFound(true)
        } else {
          setDetail(d)
          const typeRow = postsRes?.types.find((t) => t.slug === slug)
          setPostCount(typeRow?.postCount ?? null)
        }
        setLoading(false)
      })
      .catch((err: unknown) => {
        if (cancelled) return
        setError(err instanceof Error ? err.message : 'Failed to load post type')
        setLoading(false)
      })
    return () => {
      cancelled = true
    }
  }, [slug, refreshToken])

  if (loading) return <EditorSkeleton />

  if (notFound) {
    return (
      <CenteredNotice
        title={`No post type named "${slug}"`}
        body="It may have been removed from actuate.config.ts."
        actionLabel="Back to Post Types"
        onAction={() => onNavigate('/posts/types')}
      />
    )
  }

  if (error || !detail) {
    return (
      <CenteredNotice
        title={error ?? 'Failed to load post type'}
        actionLabel="Try again"
        onAction={() => setRefreshToken((t) => t + 1)}
      />
    )
  }

  return (
    <div className="flex h-full flex-col">
      <EditorToolbar detail={detail} postCount={postCount} onNavigate={onNavigate} />
      <div className="flex min-h-0 flex-1 flex-col gap-6 overflow-y-auto p-4 sm:p-6 lg:flex-row lg:items-start lg:overflow-hidden">
        <IdentityPanel detail={detail} />
        <FieldBuilder detail={detail} />
      </div>
    </div>
  )
}

// ─── Toolbar ─────────────────────────────────────────────────────────

function EditorToolbar({
  detail,
  postCount,
  onNavigate,
}: {
  detail: PostTypeDetail
  postCount: number | null
  onNavigate: (path: string) => void
}) {
  const palette = paletteFor(detail.color)
  return (
    <div className="border-border bg-card flex flex-wrap items-center gap-3 border-b px-6 py-4 sm:px-6">
      <nav aria-label="Breadcrumb" className="flex min-w-0 items-center gap-1.5 text-sm">
        <button
          type="button"
          onClick={() => onNavigate('/posts/types')}
          className="text-muted-foreground hover:text-foreground transition-colors"
        >
          Post Types
        </button>
        <ChevronRight className="text-muted-foreground h-3.5 w-3.5 shrink-0" aria-hidden />
        <span className="text-foreground truncate font-medium">{detail.plural}</span>
      </nav>
      {postCount !== null && (
        <span
          className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium tabular-nums ${palette.bg} ${palette.text}`}
        >
          {postCount} {postCount === 1 ? 'post' : 'posts'}
        </span>
      )}
      <div className="ml-auto flex items-center gap-2">
        <button
          type="button"
          onClick={() => onNavigate(`/posts/types/${detail.slug}/template`)}
          className="border-border text-foreground hover:bg-accent focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-lg border px-3 py-1.5 text-sm font-medium transition-colors focus:outline-none focus-visible:ring-2"
        >
          <LayoutTemplate className="h-3.5 w-3.5" aria-hidden />
          Edit template
        </button>
        <button
          type="button"
          onClick={() => onNavigate('/posts')}
          className="bg-primary text-primary-foreground hover:bg-primary/90 focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium shadow-sm transition-colors focus:outline-none focus-visible:ring-2"
        >
          <ExternalLink className="h-3.5 w-3.5" aria-hidden />
          View posts
        </button>
      </div>
    </div>
  )
}

// ─── Identity panel (left, 340px) ────────────────────────────────────

function IdentityPanel({ detail }: { detail: PostTypeDetail }) {
  const palette = paletteFor(detail.color)
  const Icon = resolvePostTypeIcon(detail.icon)
  return (
    <aside
      aria-label="Post type identity"
      className="flex w-full shrink-0 flex-col gap-5 lg:max-h-full lg:w-[340px] lg:overflow-y-auto"
    >
      <IdentitySection title="Identity">
        <ReadOnlyField label="Type Name" value={detail.plural} />
        <ReadOnlyField label="API Slug" value={detail.slug} mono />
        <ReadOnlyField
          label="Description"
          value={detail.description ?? 'No description provided.'}
        />
        <p className="text-muted-foreground text-xs">
          Identity and fields are defined in <code className="font-mono">actuate.config.ts</code>{' '}
          under <code className="font-mono">collections.{detail.slug}</code>. Edit the config and
          redeploy to change them.
        </p>
      </IdentitySection>

      <IdentitySection title="Icon & color">
        <div className="flex items-center gap-3">
          <span
            className={`inline-flex h-10 w-10 items-center justify-center rounded-lg ${palette.bg} ${palette.text}`}
          >
            <Icon className="h-5 w-5" aria-hidden />
          </span>
          <div className="flex flex-col gap-0.5 text-sm">
            <span className="text-foreground font-medium">{detail.icon ?? 'file-text'}</span>
            <span className="text-muted-foreground text-xs">
              Accent: {detail.color ?? 'default'}
            </span>
          </div>
        </div>
      </IdentitySection>

      <IdentitySection title="API preview">
        <div className="border-border bg-muted flex flex-col gap-1.5 overflow-x-auto rounded-lg border p-3 font-mono text-xs">
          <ApiRow method="GET" path={`/api/cms/collections/${detail.slug}`} />
          <ApiRow method="GET" path={`/api/cms/collections/${detail.slug}/{id}`} />
          <ApiRow method="POST" path={`/api/cms/collections/${detail.slug}`} />
        </div>
      </IdentitySection>
    </aside>
  )
}

function IdentitySection({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <section className="bg-card border-border flex flex-col gap-3 rounded-xl border p-5 shadow-sm">
      <h2 className="text-muted-foreground text-xs font-medium tracking-wide uppercase">{title}</h2>
      {children}
    </section>
  )
}

function ReadOnlyField({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
  return (
    <div className="flex flex-col gap-1">
      <span className="text-foreground text-sm font-medium">{label}</span>
      <div
        className={`border-border bg-muted text-foreground rounded-lg border px-3 py-1.5 text-sm ${mono ? 'font-mono' : ''}`}
      >
        {value}
      </div>
    </div>
  )
}

function ApiRow({ method, path }: { method: 'GET' | 'POST'; path: string }) {
  return (
    <div className="flex items-center gap-2 whitespace-nowrap">
      <span
        className={`w-10 shrink-0 font-medium ${method === 'GET' ? 'text-success' : 'text-info'}`}
      >
        {method}
      </span>
      <span className="text-muted-foreground">{path}</span>
    </div>
  )
}

// ─── Field builder (right) ───────────────────────────────────────────

function FieldBuilder({ detail }: { detail: PostTypeDetail }) {
  return (
    <div className="flex min-w-0 flex-1 flex-col gap-4 lg:max-h-full lg:overflow-y-auto">
      <div className="flex flex-col gap-0.5">
        <h2 className="text-foreground text-base font-medium">Field Builder</h2>
        <p className="text-muted-foreground text-sm">
          {detail.fields.length} {detail.fields.length === 1 ? 'field' : 'fields'} defined in{' '}
          <code className="font-mono">actuate.config.ts</code>
        </p>
      </div>
      <FieldList detail={detail} />
      <AddFieldCard detail={detail} />
    </div>
  )
}

function FieldList({ detail }: { detail: PostTypeDetail }) {
  return (
    <div className="bg-card border-border rounded-xl border shadow-sm">
      <div className="border-border flex items-center gap-2 border-b px-6 py-4">
        <Lock className="text-muted-foreground h-3.5 w-3.5" aria-hidden />
        <span className="text-foreground text-sm font-medium">Fields</span>
        <span className="bg-muted text-muted-foreground ml-auto rounded-full px-2 py-0.5 text-xs font-medium">
          Defined in code · {detail.fields.length} {detail.fields.length === 1 ? 'field' : 'fields'}
        </span>
      </div>
      {detail.fields.length === 0 ? (
        <p className="text-muted-foreground px-4 py-6 text-center text-sm">
          This type has no fields yet. Add one below.
        </p>
      ) : (
        <ul className="divide-border divide-y">
          {detail.fields.map((f) => (
            <li key={f.name} className="flex items-center gap-3 px-4 py-2.5">
              <Lock className="text-muted-foreground h-3.5 w-3.5 shrink-0" aria-hidden />
              <div className="flex min-w-0 flex-col">
                <span className="text-foreground truncate text-sm font-medium">
                  {humanizeFieldName(f.name)}
                </span>
                <span className="text-muted-foreground truncate font-mono text-xs">{f.name}</span>
              </div>
              <span className="border-border text-muted-foreground ml-auto shrink-0 rounded-full border px-2 py-0.5 text-xs">
                {fieldTypeLabel(f.type)}
              </span>
              <span
                className={`shrink-0 rounded-full px-2 py-0.5 text-xs font-medium ${
                  f.required
                    ? 'bg-destructive/10 text-destructive'
                    : 'bg-muted text-muted-foreground'
                }`}
              >
                {f.required ? 'Required' : 'Optional'}
              </span>
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}

// ─── Add Field (snippet generator) ───────────────────────────────────

function AddFieldCard({ detail }: { detail: PostTypeDetail }) {
  const [open, setOpen] = useState(false)
  const [fieldType, setFieldType] = useState<string | null>(null)
  const [name, setName] = useState('')
  const [helpText, setHelpText] = useState('')
  const [required, setRequired] = useState(false)
  const [copied, setCopied] = useState(false)

  const key = useMemo(() => fieldKeyFromName(name), [name])
  const existingKeys = useMemo(() => new Set(detail.fields.map((f) => f.name)), [detail.fields])
  const duplicate = key !== '' && existingKeys.has(key)

  const snippet = useMemo(() => {
    if (!fieldType || !key) return ''
    return renderFieldSnippet({
      key,
      label: name.trim() || humanizeFieldName(key),
      type: fieldType,
      required,
      helpText,
    })
  }, [fieldType, key, name, required, helpText])

  const reset = () => {
    setFieldType(null)
    setName('')
    setHelpText('')
    setRequired(false)
    setCopied(false)
  }

  const copy = async () => {
    try {
      await navigator.clipboard.writeText(snippet)
      setCopied(true)
      toast.success('Field snippet copied — paste it into the fields map')
      setTimeout(() => setCopied(false), 1800)
    } catch {
      toast.error('Copy failed — select the snippet manually')
    }
  }

  if (!open) {
    return (
      <button
        type="button"
        onClick={() => setOpen(true)}
        className="border-border text-muted-foreground hover:text-foreground hover:border-primary/50 hover:bg-primary/5 focus-visible:ring-ring flex items-center justify-center gap-2 rounded-xl border-2 border-dashed px-4 py-4 text-sm font-medium transition-colors focus:outline-none focus-visible:ring-2"
      >
        <Plus className="h-4 w-4" aria-hidden />
        Add Field
      </button>
    )
  }

  return (
    <div className="bg-card border-border flex flex-col gap-4 rounded-xl border p-5 shadow-sm">
      <div className="flex items-center justify-between">
        <h3 className="text-foreground text-sm font-medium">Add Field</h3>
        <button
          type="button"
          onClick={() => {
            reset()
            setOpen(false)
          }}
          className="text-muted-foreground hover:text-foreground text-sm transition-colors"
        >
          Cancel
        </button>
      </div>

      {/* Field type picker */}
      <div
        role="radiogroup"
        aria-label="Field type"
        className="grid grid-cols-2 gap-2 sm:grid-cols-3 xl:grid-cols-4"
      >
        {ADDABLE_FIELD_TYPES.map((t) => {
          const selected = fieldType === t.type
          return (
            <button
              key={t.type}
              type="button"
              role="radio"
              aria-checked={selected}
              onClick={() => setFieldType(t.type)}
              className={`focus-visible:ring-ring flex flex-col items-start gap-0.5 rounded-lg border p-2.5 text-left transition-colors focus:outline-none focus-visible:ring-2 ${
                selected
                  ? 'border-primary bg-primary/5'
                  : 'border-border hover:border-primary/40 hover:bg-accent'
              }`}
            >
              <span className="text-foreground text-sm font-medium">{fieldTypeLabel(t.type)}</span>
              <span className="text-muted-foreground text-xs">{t.desc}</span>
            </button>
          )
        })}
      </div>

      {fieldType && (
        <>
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
            <div className="flex flex-col gap-1">
              <label htmlFor="af-name" className="text-foreground text-sm font-medium">
                Field Name
              </label>
              <input
                id="af-name"
                value={name}
                onChange={(e) => setName(e.target.value)}
                placeholder="e.g. Client Name"
                className="border-border bg-background text-foreground focus:border-primary focus:ring-primary/30 w-full rounded-lg border px-3 py-1.5 text-sm focus:ring-2 focus:outline-none"
              />
            </div>
            <div className="flex flex-col gap-1">
              <label htmlFor="af-key" className="text-foreground text-sm font-medium">
                Field Key
              </label>
              <input
                id="af-key"
                value={key}
                readOnly
                aria-describedby={duplicate ? 'af-key-error' : undefined}
                className="border-border bg-muted text-muted-foreground w-full rounded-lg border px-3 py-1.5 font-mono text-sm focus:outline-none"
              />
              {duplicate && (
                <span id="af-key-error" className="text-destructive text-xs">
                  A field named <code className="font-mono">{key}</code> already exists on this
                  type.
                </span>
              )}
            </div>
          </div>
          <div className="flex flex-col gap-1">
            <label htmlFor="af-help" className="text-foreground text-sm font-medium">
              Help Text (optional)
            </label>
            <input
              id="af-help"
              value={helpText}
              onChange={(e) => setHelpText(e.target.value)}
              placeholder="Shown to editors as a hint"
              className="border-border bg-background text-foreground focus:border-primary focus:ring-primary/30 w-full rounded-lg border px-3 py-1.5 text-sm focus:ring-2 focus:outline-none"
            />
          </div>
          <div className="flex items-center gap-2">
            <Toggle
              id="af-required"
              checked={required}
              onCheckedChange={setRequired}
              aria-labelledby="af-required-label"
            />
            <label id="af-required-label" htmlFor="af-required" className="text-foreground text-sm">
              Required field
            </label>
          </div>

          {snippet && !duplicate && (
            <div className="flex flex-col gap-2">
              <div className="flex items-center justify-between">
                <span className="text-foreground text-sm font-medium">
                  Add to <code className="font-mono">collections.{detail.slug}.fields</code>
                </span>
                <button
                  type="button"
                  onClick={copy}
                  className="border-border bg-background text-foreground hover:bg-accent inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs font-medium transition-colors"
                >
                  {copied ? (
                    <Check className="h-3.5 w-3.5" aria-hidden />
                  ) : (
                    <Copy className="h-3.5 w-3.5" aria-hidden />
                  )}
                  {copied ? 'Copied' : 'Copy snippet'}
                </button>
              </div>
              <pre className="border-border bg-muted text-foreground overflow-x-auto rounded-lg border p-3 text-xs leading-relaxed">
                <code>{snippet}</code>
              </pre>
              <p className="text-muted-foreground text-xs">
                Paste the line into the type&apos;s <code className="font-mono">fields</code> map in{' '}
                <code className="font-mono">actuate.config.ts</code> and redeploy — the field
                appears in the editor automatically.
              </p>
            </div>
          )}
        </>
      )}
    </div>
  )
}

// ─── Loading / notice states ─────────────────────────────────────────

function EditorSkeleton() {
  return (
    <div className="flex h-full flex-col">
      <div className="border-border bg-card border-b px-6 py-4 sm:px-6">
        <div className="bg-muted h-5 w-48 animate-pulse rounded" />
      </div>
      <div className="flex flex-col gap-6 p-4 sm:p-6 lg:flex-row">
        <div className="flex w-full flex-col gap-4 lg:w-[340px]">
          {Array.from({ length: 3 }).map((_, i) => (
            <div key={i} className="bg-card border-border h-32 animate-pulse rounded-xl border" />
          ))}
        </div>
        <div className="bg-card border-border h-64 flex-1 animate-pulse rounded-xl border" />
      </div>
    </div>
  )
}

function CenteredNotice({
  title,
  body,
  actionLabel,
  onAction,
}: {
  title: string
  body?: string
  actionLabel: string
  onAction: () => void
}) {
  return (
    <div className="flex h-full flex-col items-center justify-center gap-2 p-8 text-center">
      <FileQuestion className="text-muted-foreground h-6 w-6" aria-hidden />
      <div className="text-foreground text-sm font-medium">{title}</div>
      {body && <p className="text-muted-foreground text-sm">{body}</p>}
      <button
        type="button"
        onClick={onAction}
        className="text-primary mt-2 text-sm font-medium hover:underline"
      >
        {actionLabel}
      </button>
    </div>
  )
}
