import { useCallback, useEffect, useState } from 'react'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import {
  ArrowDown,
  ArrowUp,
  Check,
  ChevronDown,
  Columns2,
  GripVertical,
  Image,
  Layout,
  Loader2,
  MessageSquareQuote,
  Monitor,
  Newspaper,
  Play,
  Plus,
  RectangleHorizontal,
  RefreshCw,
  SquareStack,
  Trash2,
  Type,
  X,
} from 'lucide-react'
import type { BlockApi } from '@/lib/api/blocks'
import type { AdminPageBlockRecord } from '@/lib/api/types'
import { handleServerError } from '@/lib/handle-server-error'
import { cn } from '@/lib/utils'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { blockTypes, getBlockTypeLabel } from './block-helpers'
import {
  BlockContentFields,
  contentToFieldValues,
  fieldValuesToContent,
  getBlockPreviewText,
} from './block-content-fields'

const blockIconMap: Record<string, React.ElementType> = {
  hero: Monitor,
  text: Type,
  text_image: Newspaper,
  stats_grid: SquareStack,
  cta: Layout,
  faq: MessageSquareQuote,
  gallery: Image,
  video: Play,
  cards: SquareStack,
  testimonials: MessageSquareQuote,
  html: Type,
}

function getBlockIcon(type: string) {
  return blockIconMap[type] ?? Type
}

/* ------------------------------------------------------------------ */
/*  Inline block card                                                  */
/* ------------------------------------------------------------------ */

function BlockCard({
  block,
  index,
  totalBlocks,
  isExpanded,
  onToggle,
  onSave,
  onDelete,
  onMove,
  isSaving,
  isReordering,
}: {
  block: AdminPageBlockRecord
  index: number
  totalBlocks: number
  isExpanded: boolean
  onToggle: () => void
  onSave: (type: string, content: Record<string, unknown>) => void
  onDelete: () => void
  onMove: (direction: 'up' | 'down') => void
  isSaving: boolean
  isReordering: boolean
}) {
  const currentWidth =
    (block.content?.['_width'] as string | undefined) ?? 'full'
  const [fieldValues, setFieldValues] = useState<Record<string, string>>(() =>
    contentToFieldValues(block.type, block.content)
  )
  const [editType, setEditType] = useState(block.type)
  const [width, setWidth] = useState<'full' | 'half'>(
    currentWidth === 'half' ? 'half' : 'full'
  )
  const [dirty, setDirty] = useState(false)

  useEffect(() => {
    setFieldValues(contentToFieldValues(block.type, block.content))
    setEditType(block.type)
    setWidth(
      (block.content?.['_width'] as string | undefined) === 'half'
        ? 'half'
        : 'full'
    )
    setDirty(false)
  }, [block])

  function handleFieldChange(next: Record<string, string>) {
    setFieldValues(next)
    setDirty(true)
  }

  function handleTypeChange(nextType: string) {
    setEditType(nextType)
    setFieldValues(contentToFieldValues(nextType, null))
    setDirty(true)
  }

  function handleWidthToggle() {
    const next = width === 'full' ? 'half' : 'full'
    setWidth(next)
    setDirty(true)
  }

  function handleSave() {
    const content = fieldValuesToContent(fieldValues)
    content['_width'] = width
    onSave(editType, content)
  }

  const Icon = getBlockIcon(block.type)
  const preview = getBlockPreviewText(block.type, block.content)

  return (
    <div
      className={cn(
        'overflow-hidden rounded-2xl border bg-card shadow-sm transition-all',
        isExpanded
          ? 'border-primary/30 ring-1 ring-primary/10'
          : 'border-border/70 hover:border-border'
      )}
    >
      <div className='flex items-center gap-2 px-3 py-2.5'>
        <div className='flex flex-col gap-0.5'>
          <Button
            type='button'
            variant='ghost'
            size='icon'
            className='size-5 rounded'
            disabled={index === 0 || isReordering}
            onClick={() => onMove('up')}
          >
            <ArrowUp className='size-3' />
          </Button>
          <Button
            type='button'
            variant='ghost'
            size='icon'
            className='size-5 rounded'
            disabled={index === totalBlocks - 1 || isReordering}
            onClick={() => onMove('down')}
          >
            <ArrowDown className='size-3' />
          </Button>
        </div>

        <GripVertical className='size-4 shrink-0 text-muted-foreground/40' />

        <button
          type='button'
          onClick={onToggle}
          className='flex min-w-0 flex-1 items-center gap-3 text-left'
        >
          <div className='flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-muted'>
            <Icon className='size-4 text-muted-foreground' />
          </div>
          <div className='min-w-0 flex-1'>
            <div className='flex items-center gap-2'>
              <Badge
                variant='outline'
                className='shrink-0 rounded-full text-xs'
              >
                {getBlockTypeLabel(block.type)}
              </Badge>
              <Badge
                variant={width === 'half' ? 'default' : 'secondary'}
                className='shrink-0 rounded-full px-1.5 py-0 text-[10px]'
              >
                {width === 'half' ? '½ Yarım' : 'Tam'}
              </Badge>
              <span className='text-xs text-muted-foreground'>
                #{index + 1}
              </span>
            </div>
            {!isExpanded && (
              <p className='mt-0.5 truncate text-xs text-muted-foreground'>
                {preview}
              </p>
            )}
          </div>
          <ChevronDown
            className={cn(
              'size-4 shrink-0 text-muted-foreground transition-transform',
              isExpanded && 'rotate-180'
            )}
          />
        </button>

        <Button
          type='button'
          variant='ghost'
          size='icon'
          className='size-8 shrink-0 text-destructive hover:bg-destructive/10 hover:text-destructive'
          onClick={onDelete}
        >
          <Trash2 className='size-3.5' />
        </Button>
      </div>

      {isExpanded && (
        <div className='border-t border-border/50 bg-muted/5 px-4 py-4'>
          <div className='mb-4 flex flex-wrap items-center gap-3'>
            <div className='max-w-xs flex-1'>
              <Select value={editType} onValueChange={handleTypeChange}>
                <SelectTrigger className='rounded-xl'>
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {blockTypes.map((bt) => (
                    <SelectItem key={bt.value} value={bt.value}>
                      {bt.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className='flex items-center gap-1 rounded-xl border border-border/70 p-0.5'>
              <Button
                type='button'
                variant={width === 'full' ? 'default' : 'ghost'}
                size='sm'
                className='h-7 gap-1 rounded-lg px-2 text-xs'
                onClick={() => {
                  if (width !== 'full') handleWidthToggle()
                }}
              >
                <RectangleHorizontal className='size-3' />
                Tam
              </Button>
              <Button
                type='button'
                variant={width === 'half' ? 'default' : 'ghost'}
                size='sm'
                className='h-7 gap-1 rounded-lg px-2 text-xs'
                onClick={() => {
                  if (width !== 'half') handleWidthToggle()
                }}
              >
                <Columns2 className='size-3' />
                Yarım
              </Button>
            </div>
          </div>

          <BlockContentFields
            type={editType}
            values={fieldValues}
            onChange={handleFieldChange}
          />

          <div className='mt-4 flex items-center justify-end gap-2 border-t border-border/50 pt-3'>
            {dirty && (
              <span className='mr-auto text-xs text-amber-600'>
                Kaydedilmemiş değişiklikler
              </span>
            )}
            <Button
              type='button'
              size='sm'
              className='rounded-xl'
              disabled={!dirty || isSaving}
              onClick={handleSave}
            >
              {isSaving ? <Loader2 className='animate-spin' /> : <Check />}
              Kaydet
            </Button>
          </div>
        </div>
      )}
    </div>
  )
}

/* ------------------------------------------------------------------ */
/*  New block picker                                                   */
/* ------------------------------------------------------------------ */

function NewBlockPicker({
  onAdd,
  isPending,
}: {
  onAdd: (type: string) => void
  isPending: boolean
}) {
  const [open, setOpen] = useState(false)

  if (!open) {
    return (
      <button
        type='button'
        onClick={() => setOpen(true)}
        className='flex w-full items-center justify-center gap-2 rounded-2xl border-2 border-dashed border-border/60 py-4 text-sm text-muted-foreground transition hover:border-primary/40 hover:text-foreground'
      >
        <Plus className='size-4' />
        Yeni blok ekle
      </button>
    )
  }

  return (
    <div className='rounded-2xl border border-primary/20 bg-card p-4 shadow-sm'>
      <div className='mb-3 flex items-center justify-between'>
        <p className='text-sm font-medium'>Blok tipi seçin</p>
        <Button
          type='button'
          variant='ghost'
          size='icon'
          className='size-7'
          onClick={() => setOpen(false)}
        >
          <X className='size-4' />
        </Button>
      </div>
      <div className='grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-4'>
        {blockTypes.map((bt) => {
          const BtIcon = getBlockIcon(bt.value)
          return (
            <button
              key={bt.value}
              type='button'
              disabled={isPending}
              onClick={() => {
                onAdd(bt.value)
                setOpen(false)
              }}
              className='flex flex-col items-center gap-1.5 rounded-xl border border-border/70 bg-background p-3 text-center transition hover:border-primary/40 hover:bg-primary/5 disabled:opacity-50'
            >
              <BtIcon className='size-5 text-muted-foreground' />
              <span className='text-xs font-medium'>{bt.label}</span>
            </button>
          )
        })}
      </div>
    </div>
  )
}

/* ------------------------------------------------------------------ */
/*  Block manager (generic)                                            */
/* ------------------------------------------------------------------ */

export function BlockManager({ api }: { api: BlockApi }) {
  const queryClient = useQueryClient()
  const [expandedId, setExpandedId] = useState<number | string | null>(null)
  const [blockToDelete, setBlockToDelete] =
    useState<AdminPageBlockRecord | null>(null)

  const blocksQuery = useQuery({
    queryKey: [...api.queryKey],
    queryFn: () => api.fetchBlocks(),
  })

  const blocks = blocksQuery.data ?? []

  const invalidateBlocks = useCallback(async () => {
    await queryClient.invalidateQueries({ queryKey: [...api.queryKey] })
    await queryClient.invalidateQueries({ queryKey: [...api.parentQueryKey] })
  }, [queryClient, api.queryKey, api.parentQueryKey])

  const addBlockMutation = useMutation({
    mutationFn: async (type: string) =>
      api.createBlock({
        type,
        content: { title: '' },
        order_index: blocks.length,
      }),
    onSuccess: async (newBlock) => {
      await invalidateBlocks()
      setExpandedId(newBlock.id)
      toast.success('Blok eklendi')
    },
    onError: handleServerError,
  })

  const updateBlockMutation = useMutation({
    mutationFn: async ({
      blockId,
      type,
      content,
    }: {
      blockId: number | string
      type: string
      content: Record<string, unknown>
    }) => api.updateBlock(blockId, { type, content }),
    onSuccess: async () => {
      await invalidateBlocks()
      toast.success('Blok güncellendi')
    },
    onError: handleServerError,
  })

  const deleteBlockMutation = useMutation({
    mutationFn: async (blockId: number | string) => api.deleteBlock(blockId),
    onSuccess: async () => {
      await invalidateBlocks()
      setBlockToDelete(null)
      setExpandedId(null)
      toast.success('Blok silindi')
    },
    onError: handleServerError,
  })

  const reorderMutation = useMutation({
    mutationFn: async (
      items: Array<{ id: number | string; order_index: number }>
    ) => api.reorderBlocks(items),
    onSuccess: async () => {
      await invalidateBlocks()
    },
    onError: handleServerError,
  })

  function moveBlock(index: number, direction: 'up' | 'down') {
    const swapIndex = direction === 'up' ? index - 1 : index + 1
    if (swapIndex < 0 || swapIndex >= blocks.length) return

    const reordered = [...blocks]
    const temp = reordered[index]
    reordered[index] = reordered[swapIndex]
    reordered[swapIndex] = temp

    reorderMutation.mutate(
      reordered.map((block, idx) => ({ id: block.id, order_index: idx }))
    )
  }

  return (
    <div className='space-y-3'>
      <div className='flex items-center justify-between'>
        <div>
          <p className='text-sm font-semibold'>İçerik Blokları</p>
          <p className='text-xs text-muted-foreground'>
            {blocks.length} blok — Blokları sıralayın, düzenleyin veya
            yenilerini ekleyin
          </p>
        </div>
        <Button
          type='button'
          variant='outline'
          size='sm'
          className='rounded-xl'
          onClick={() => blocksQuery.refetch()}
          disabled={blocksQuery.isFetching}
        >
          <RefreshCw
            className={blocksQuery.isFetching ? 'animate-spin' : ''}
          />
        </Button>
      </div>

      {blocksQuery.isLoading ? (
        <div className='flex items-center justify-center rounded-2xl border border-dashed border-border/70 py-12 text-muted-foreground'>
          <Loader2 className='mr-2 size-5 animate-spin' />
          Bloklar yükleniyor...
        </div>
      ) : (
        <div className='space-y-2'>
          {blocks.map((block, index) => (
            <BlockCard
              key={block.id}
              block={block}
              index={index}
              totalBlocks={blocks.length}
              isExpanded={expandedId === block.id}
              onToggle={() =>
                setExpandedId(expandedId === block.id ? null : block.id)
              }
              onSave={(type, content) =>
                updateBlockMutation.mutate({
                  blockId: block.id,
                  type,
                  content,
                })
              }
              onDelete={() => setBlockToDelete(block)}
              onMove={(dir) => moveBlock(index, dir)}
              isSaving={updateBlockMutation.isPending}
              isReordering={reorderMutation.isPending}
            />
          ))}

          <NewBlockPicker
            onAdd={(type) => addBlockMutation.mutate(type)}
            isPending={addBlockMutation.isPending}
          />
        </div>
      )}

      <ConfirmDialog
        open={!!blockToDelete}
        onOpenChange={(open) => {
          if (!open) setBlockToDelete(null)
        }}
        title='Bloğu silmek istediğinize emin misiniz?'
        desc={`"${getBlockTypeLabel(blockToDelete?.type ?? '')}" bloğu kalıcı olarak silinecek.`}
        confirmText='Evet, sil'
        cancelBtnText='İptal'
        destructive
        isLoading={deleteBlockMutation.isPending}
        handleConfirm={() => {
          if (blockToDelete) {
            deleteBlockMutation.mutate(blockToDelete.id)
          }
        }}
      />
    </div>
  )
}
