'use client'

import { useState, useMemo, useCallback } from 'react'
import { Star, Copy, Trash2 } from 'lucide-react'
import * as SwitchPrimitive from '@radix-ui/react-switch'
import type { BlockNode, BlockTypeDefinition, FieldDefinition } from '@actuate-media/cms-core'
import { BlockCatalog } from '@actuate-media/cms-core/page-builder'
import { AIBlockAssist } from './AIBlockAssist.js'
import { RelationshipField } from './RelationshipField.js'
import { TipTapEditor } from '../../components/TipTapEditor.js'
import { MediaPickerModal } from '../../components/MediaPickerModal.js'

export interface BlockEditorProps {
  node: BlockNode
  onUpdateBlock: (id: string, data: Record<string, unknown>) => void
  onUpdateSettings: (id: string, settings: Record<string, unknown>) => void
  onRemoveNode: (id: string) => void
  onDuplicateNode: (id: string) => void
  config: any
}

const INPUT_CLASS =
  'w-full px-3 py-2 text-sm bg-background border border-input rounded-md focus:outline-none focus:ring-2 focus:ring-ring'
const LABEL_CLASS = 'text-sm font-medium text-foreground mb-1 block'

export function BlockEditor({
  node,
  onUpdateBlock,
  onUpdateSettings,
  onRemoveNode,
  onDuplicateNode,
  config,
}: BlockEditorProps) {
  const [confirmDelete, setConfirmDelete] = useState(false)

  const catalog = useMemo(() => new BlockCatalog(), [])
  const blockDef = useMemo(
    () => catalog.get(node.settings.blockType),
    [catalog, node.settings.blockType],
  )

  const handleFieldChange = useCallback(
    (fieldName: string, value: unknown) => {
      onUpdateBlock(node.id, { [fieldName]: value })
    },
    [node.id, onUpdateBlock],
  )

  const handleVariantChange = useCallback(
    (variantName: string) => {
      onUpdateSettings(node.id, { variant: variantName })
    },
    [node.id, onUpdateSettings],
  )

  const handleDelete = useCallback(() => {
    if (confirmDelete) {
      onRemoveNode(node.id)
      setConfirmDelete(false)
    } else {
      setConfirmDelete(true)
    }
  }, [confirmDelete, node.id, onRemoveNode])

  if (!blockDef) {
    return (
      <div className="p-4">
        <p className="text-muted-foreground text-sm">
          Unknown block type: <code className="text-xs">{node.settings.blockType}</code>
        </p>
      </div>
    )
  }

  return (
    <div className="flex h-full flex-col">
      <div className="border-border border-b p-4">
        <div className="flex items-center gap-2">
          <Star size={16} className="text-muted-foreground" />
          <span className="text-foreground flex-1 text-sm font-medium">{blockDef.label}</span>
          <AIBlockAssist block={node} onUpdateData={(data) => onUpdateBlock(node.id, data)} />
        </div>
        {blockDef.description && (
          <p className="text-muted-foreground mt-1 text-xs">{blockDef.description}</p>
        )}
      </div>

      {blockDef.variants.length > 1 && (
        <div className="border-border border-b p-4">
          <p className="text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase">
            Variant
          </p>
          <div className="grid grid-cols-2 gap-1.5">
            {blockDef.variants.map((variant) => (
              <button
                key={variant.name}
                type="button"
                onClick={() => handleVariantChange(variant.name)}
                className={`rounded-md border px-2 py-1.5 text-xs transition-colors ${
                  node.settings.variant === variant.name
                    ? 'bg-primary text-primary-foreground border-primary'
                    : 'bg-background border-input text-foreground hover:bg-accent'
                }`}
              >
                {variant.label}
              </button>
            ))}
          </div>
        </div>
      )}

      <div className="flex-1 space-y-4 p-4">
        <p className="text-muted-foreground mb-2 text-xs font-medium tracking-wider uppercase">
          Fields
        </p>
        {Object.entries(blockDef.fields).map(([fieldName, fieldDef]) => (
          <FieldRenderer
            key={fieldName}
            name={fieldName}
            definition={fieldDef}
            value={node.data[fieldName]}
            onChange={(value) => handleFieldChange(fieldName, value)}
          />
        ))}
      </div>

      <div className="border-border space-y-2 border-t p-4">
        <button
          type="button"
          onClick={() => onDuplicateNode(node.id)}
          className="bg-background border-input hover:bg-accent flex w-full items-center justify-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors"
        >
          <Copy size={14} />
          Duplicate
        </button>
        <button
          type="button"
          onClick={handleDelete}
          onBlur={() => setConfirmDelete(false)}
          className={`flex w-full items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors ${
            confirmDelete
              ? 'bg-destructive text-destructive-foreground'
              : 'bg-background border-destructive text-destructive hover:bg-destructive/10 border'
          }`}
        >
          <Trash2 size={14} />
          {confirmDelete ? 'Click again to confirm' : 'Delete'}
        </button>
      </div>
    </div>
  )
}

interface FieldRendererProps {
  name: string
  definition: FieldDefinition
  value: unknown
  onChange: (value: unknown) => void
}

function FieldRenderer({ name, definition, value, onChange }: FieldRendererProps) {
  const label = definition.label || name

  switch (definition.type) {
    case 'text':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <input
            type="text"
            value={(value as string) ?? ''}
            onChange={(e) => onChange(e.target.value)}
            placeholder={definition.admin?.placeholder}
            className={INPUT_CLASS}
          />
        </div>
      )

    case 'richText':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <div className="border-input bg-background overflow-hidden rounded-md border">
            <TipTapEditor
              content={(value as string) ?? ''}
              onChange={(html) => onChange(html)}
              placeholder={definition.admin?.placeholder}
            />
          </div>
        </div>
      )

    case 'url':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <input
            type="url"
            value={(value as string) ?? ''}
            onChange={(e) => onChange(e.target.value)}
            placeholder={definition.admin?.placeholder ?? 'https://'}
            className={INPUT_CLASS}
          />
        </div>
      )

    case 'number':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <input
            type="number"
            value={(value as number) ?? ''}
            onChange={(e) => onChange(e.target.value ? Number(e.target.value) : undefined)}
            min={definition.min}
            max={definition.max}
            step={definition.step}
            className={INPUT_CLASS}
          />
        </div>
      )

    case 'boolean':
      return (
        <div className="flex items-center justify-between">
          <label className="text-foreground text-sm font-medium">{label}</label>
          <SwitchPrimitive.Root
            checked={!!value}
            onCheckedChange={(checked) => onChange(checked)}
            className="bg-input data-[state=checked]:bg-primary relative h-5 w-9 rounded-full transition-colors"
            aria-label={label}
          >
            <SwitchPrimitive.Thumb className="bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[18px]" />
          </SwitchPrimitive.Root>
        </div>
      )

    case 'media':
      return <MediaFieldRenderer label={label} value={value} onChange={onChange} />

    case 'select':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <select
            value={(value as string) ?? ''}
            onChange={(e) => onChange(e.target.value)}
            className={INPUT_CLASS}
          >
            <option value="">Select...</option>
            {definition.options.map((opt) => (
              <option key={opt.value} value={opt.value}>
                {opt.label}
              </option>
            ))}
          </select>
        </div>
      )

    case 'array':
      return <ArrayFieldRenderer label={label} value={value} onChange={onChange} />

    case 'json':
      return <JsonFieldRenderer label={label} value={value} onChange={onChange} />

    case 'date':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <input
            type="date"
            value={typeof value === 'string' && value ? value.slice(0, 10) : ''}
            onChange={(e) => onChange(e.target.value || undefined)}
            className={INPUT_CLASS}
          />
        </div>
      )

    case 'slug':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <input
            type="text"
            value={(value as string) ?? ''}
            onChange={(e) => {
              const slug = e.target.value
                .toLowerCase()
                .replace(/[^a-z0-9-]+/g, '-')
                .replace(/^-+|-+$/g, '')
              onChange(slug)
            }}
            placeholder={definition.admin?.placeholder ?? 'page-slug'}
            className={INPUT_CLASS}
          />
        </div>
      )

    case 'relationship':
      return (
        <RelationshipField
          definition={definition}
          value={value}
          onChange={onChange}
          label={label}
        />
      )

    case 'email':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <input
            type="email"
            value={(value as string) ?? ''}
            onChange={(e) => onChange(e.target.value)}
            placeholder={definition.admin?.placeholder ?? 'email@example.com'}
            className={INPUT_CLASS}
          />
        </div>
      )

    case 'color':
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <div className="flex items-center gap-2">
            <input
              type="color"
              value={(value as string) ?? '#000000'}
              onChange={(e) => onChange(e.target.value)}
              className="border-input h-9 w-9 cursor-pointer rounded-md border"
            />
            <input
              type="text"
              value={(value as string) ?? ''}
              onChange={(e) => onChange(e.target.value)}
              placeholder="#000000"
              className={`${INPUT_CLASS} flex-1`}
            />
          </div>
        </div>
      )

    default:
      return (
        <div>
          <label className={LABEL_CLASS}>{label}</label>
          <input
            type="text"
            value={String(value ?? '')}
            onChange={(e) => onChange(e.target.value)}
            className={INPUT_CLASS}
          />
        </div>
      )
  }
}

interface SimpleFieldProps {
  label: string
  value: unknown
  onChange: (value: unknown) => void
}

/**
 * Block-level media picker. Wires the cross-cutting MediaPickerModal so
 * custom blocks declared with `type: 'media'` actually get a working
 * browse-and-select flow instead of a free-text input.
 */
function MediaFieldRenderer({ label, value, onChange }: SimpleFieldProps) {
  const [open, setOpen] = useState(false)
  const url =
    typeof value === 'string'
      ? value
      : value && typeof value === 'object' && 'url' in (value as any)
        ? String((value as any).url)
        : ''

  return (
    <div>
      <label className={LABEL_CLASS}>{label}</label>
      <div className="flex gap-2">
        <input
          type="text"
          value={url}
          onChange={(e) => onChange(e.target.value)}
          placeholder="https://..."
          className={`${INPUT_CLASS} flex-1`}
        />
        <button
          type="button"
          onClick={() => setOpen(true)}
          className="bg-accent text-foreground border-input hover:bg-accent/80 rounded-md border px-3 py-2 text-xs font-medium transition-colors"
        >
          Browse
        </button>
      </div>
      {url && /\.(png|jpe?g|gif|webp|avif|svg)(\?|$)/i.test(url) && (
        <div className="border-border bg-muted mt-2 overflow-hidden rounded-md border">
          {/* Plain img is fine here; admin only and we don't have next/image in scope. */}
          <img src={url} alt="" className="bg-checkered h-32 w-full object-contain" />
        </div>
      )}
      <MediaPickerModal
        open={open}
        onClose={() => setOpen(false)}
        onSelect={(selectedUrl) => {
          onChange(selectedUrl)
          setOpen(false)
        }}
      />
    </div>
  )
}

/**
 * JSON editor for free-form object/array fields. The textarea is the
 * source of truth while the user is typing — we only commit a parsed
 * value back upstream once the JSON is well-formed, otherwise the user
 * sees a validation error inline. This prevents typing-induced state
 * loss and keeps the UI usable for arrays of objects (a common shape
 * for custom blocks).
 */
function JsonFieldRenderer({ label, value, onChange }: SimpleFieldProps) {
  const initial = useMemo(() => {
    if (value === undefined || value === null) return ''
    try {
      return JSON.stringify(value, null, 2)
    } catch {
      return ''
    }
  }, [value])
  const [draft, setDraft] = useState(initial)
  const [error, setError] = useState<string | null>(null)

  const handleChange = (next: string) => {
    setDraft(next)
    if (next.trim() === '') {
      setError(null)
      onChange(undefined)
      return
    }
    try {
      onChange(JSON.parse(next))
      setError(null)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Invalid JSON')
    }
  }

  return (
    <div>
      <label className={LABEL_CLASS}>{label}</label>
      <textarea
        value={draft}
        onChange={(e) => handleChange(e.target.value)}
        rows={6}
        spellCheck={false}
        className={`${INPUT_CLASS} resize-y font-mono text-xs`}
      />
      {error && (
        <p className="text-destructive mt-1 text-xs" role="alert">
          {error}
        </p>
      )}
    </div>
  )
}

/**
 * Lightweight array editor — supports homogenous arrays of strings or
 * objects. For block fields we deliberately keep this simple: full
 * nested-field editing belongs in the document-level FieldRenderer.
 */
function ArrayFieldRenderer({ label, value, onChange }: SimpleFieldProps) {
  const items = Array.isArray(value) ? value : []
  const isObjectArray = items.length > 0 && typeof items[0] === 'object' && items[0] !== null

  if (isObjectArray) {
    // For object arrays fall back to JSON — mirrors what most consumers
    // expect when their block declares `type: 'array'` with no schema.
    return <JsonFieldRenderer label={label} value={value} onChange={onChange} />
  }

  const updateItem = (idx: number, next: string) => {
    const copy = [...items]
    copy[idx] = next
    onChange(copy)
  }
  const addItem = () => onChange([...items, ''])
  const removeItem = (idx: number) => onChange(items.filter((_, i) => i !== idx))

  return (
    <div>
      <label className={LABEL_CLASS}>{label}</label>
      <div className="space-y-2">
        {items.map((item, idx) => (
          <div key={idx} className="flex gap-2">
            <input
              type="text"
              value={typeof item === 'string' ? item : ''}
              onChange={(e) => updateItem(idx, e.target.value)}
              className={`${INPUT_CLASS} flex-1`}
            />
            <button
              type="button"
              onClick={() => removeItem(idx)}
              aria-label={`Remove item ${idx + 1}`}
              className="text-destructive border-input hover:bg-destructive/10 rounded-md border px-2 py-2 text-xs transition-colors"
            >
              <Trash2 size={14} />
            </button>
          </div>
        ))}
        <button
          type="button"
          onClick={addItem}
          className="bg-accent text-foreground border-input hover:bg-accent/80 w-full rounded-md border px-3 py-2 text-xs font-medium transition-colors"
        >
          + Add item
        </button>
      </div>
    </div>
  )
}
