import { Button, Dialog, Notification, toast } from '@/components/ui'
import { MenuDto } from '@/proxy/menus/models'
import { MenuItem } from '@/proxy/menus/menu'
import { MenuService } from '@/services/menu.service'
import { useNavigationIcons } from '@/proxy/menus/navigation-icon.config'
import { useEffect, useMemo, useRef, useState } from 'react'
import { FaChevronDown, FaEdit, FaPlus } from 'react-icons/fa'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useConfig } from '@/components/ui/ConfigProvider'
import { useForm } from '@/components/ui/Form/context'
import Input from '@/components/ui/Input'

const menuService = new MenuService()

// ─── IconPickerField ──────────────────────────────────────────────────────────

interface IconPickerFieldProps {
  value: string
  onChange: (iconKey: string) => void
  invalid?: boolean
}

const ICON_PAGE_SIZE = 100

export function IconPickerField({ value, onChange, invalid }: IconPickerFieldProps) {
  const navigationIcon = useNavigationIcons()
  // Sözlük asenkron dolduğu için liste yükleme bittiğinde yeniden türetilir.
  const allIconEntries = useMemo(() => Object.entries(navigationIcon), [navigationIcon])
  const [open, setOpen] = useState(false)
  const [search, setSearch] = useState('')
  const [limit, setLimit] = useState(ICON_PAGE_SIZE)
  const wrapperRef = useRef<HTMLDivElement>(null)

  // Tetikleyici yüksekliği, komşu Input/Select alanlarıyla aynı olsun diye
  // Input bileşeniyle birebir aynı kaynaktan (form context → global config) okunur.
  const formSize = useForm()?.size
  const { controlSize: defaultControlSize } = useConfig()
  const controlSize = formSize ?? defaultControlSize

  const SelectedIcon = value ? navigationIcon[value] : null
  const filtered = search.trim()
    ? allIconEntries.filter(([key]) => key.toLowerCase().includes(search.toLowerCase()))
    : allIconEntries
  const displayed = filtered.slice(0, limit)
  const hasMore = displayed.length < filtered.length
  const { translate } = useLocalization()

  useEffect(() => {
    setLimit(ICON_PAGE_SIZE)
  }, [search])

  useEffect(() => {
    function handleClickOutside(e: MouseEvent) {
      if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) setOpen(false)
    }
    if (open) document.addEventListener('mousedown', handleClickOutside)
    return () => document.removeEventListener('mousedown', handleClickOutside)
  }, [open])

  return (
    <div ref={wrapperRef} className="relative">
      {/*
        Tetikleyici, platformun `.input` sınıfını kullanır; böylece kenarlık, köşe
        yarıçapı, dolgu ve açık/koyu tema arka planı diğer form alanlarıyla birebir
        aynı olur. Metin renkleri `!` ile verilir: Button bileşeni variant'ına göre
        kendi `text-*` sınıfını basıyor ve aynı özgüllükte olduğu için eziyordu.
        Aynı sebeple kenarlık/arka plan da `!` ile verilir: `plain` variant
        `bg-transparent border border-transparent` bastığı için `.input` kenarlığı
        eziliyor ve alan açık temada görünmez oluyordu (yalnızca hover'da beliriyordu).
      */}
      <Button
        type="button"
        onClick={() => setOpen((v) => !v)}
        variant="plain"
        shape="round"
        size={controlSize}
        className={`input flex items-center gap-2 !justify-start !px-3 text-left text-sm !text-gray-700 dark:!text-gray-100
          !bg-white dark:!bg-transparent !border !border-gray-300 dark:!border-gray-600 hover:!border-indigo-400
          ${invalid ? 'input-invalid !border-red-500' : ''}`}
      >
        {SelectedIcon ? (
          <span className="flex items-center gap-2 flex-1 truncate">
            <SelectedIcon className="text-xl shrink-0" />
            <span className="truncate">{value}</span>
          </span>
        ) : (
          <span className="flex-1 !text-gray-400">{translate('::App.WizardStep1.SelectIcon')}</span>
        )}
        <FaChevronDown
          className={`shrink-0 text-gray-400 text-xs transition-transform ${open ? 'rotate-180' : ''}`}
        />
      </Button>

      {/*
        Panel genişliği tetikleyiciyi takip eder: sabit 360px, Visual Designer'ın dar
        property kolonunda yatay taşmaya ve ikonların sıkışmasına yol açıyordu. Alt
        sınır okunabilirliği, üst sınır geniş dialogdaki eski görünümü korur.
      */}
      {open && (
        <div className="absolute z-50 mt-1 left-0 w-full min-w-[220px] max-w-[min(360px,calc(100vw-2rem))] bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-lg shadow-xl">
          <div className="p-2 border-b border-gray-100 dark:border-gray-700 flex items-center gap-2">
            <Input
              unstyle
              autoFocus
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder="Search icons… (FaHome, FcSettings)"
              className="flex-1 px-2 py-1.5 text-sm rounded border border-gray-200 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 outline-none focus:border-indigo-400"
            />
            <span className="text-xs text-gray-400 shrink-0">{filtered.length} icons</span>
          </div>
          <div className="grid grid-cols-[repeat(auto-fill,minmax(2rem,1fr))] gap-0.5 p-2 max-h-[208px] overflow-y-auto">
            {displayed.map(([key, Icon]) => (
              <Button
                key={key}
                type="button"
                title={key}
                onClick={() => {
                  onChange(key)
                  setOpen(false)
                  setSearch('')
                }}
                variant="plain"
                shape="none"
                className={`!flex !h-10 !w-full !min-w-0 !items-center !justify-center !rounded !px-0 text-xl transition-colors
                  ${value === key ? 'bg-indigo-500 text-white' : 'hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-600 dark:text-gray-300'}`}
              >
                <Icon className="h-5 w-5" />
              </Button>
            ))}
          </div>
          {hasMore && (
            <div className="px-3 py-1.5 border-t border-gray-100 dark:border-gray-700 flex items-center justify-between">
              <span className="text-xs text-gray-400">
                {displayed.length} / {filtered.length}
              </span>
              <Button
                type="button"
                onClick={() => setLimit((l) => l + ICON_PAGE_SIZE)}
                size="xs"
                variant="solid"
              >
                {translate('::Abp.Identity.ActivityLogs.LoadMore')}
              </Button>
            </div>
          )}
        </div>
      )}
    </div>
  )
}

// ─── MenuAddDialog ────────────────────────────────────────────────────────────

export interface MenuAddDialogProps {
  isOpen: boolean
  onClose: () => void
  initialParentCode: string
  initialOrder: number
  rawItems: (MenuItem & { id?: string })[]
  /**
   * Dolu ise dialog düzenleme modunda açılır ve menünün tüm alanları değiştirilebilir.
   * Boş bırakılırsa yeni menü oluşturma modudur.
   */
  editMenu?: (MenuItem & { id?: string }) | null
  onSaved: (menu: {
    code: string
    parentCode?: string
    menuTextEn: string
    menuTextTr: string
    icon?: string
    shortName?: string
  }) => void | Promise<void>
}

/** Düzenleme modunda menü kendi alt ağacına taşınamaz; aksi halde döngü oluşur. */
function collectDescendantCodes(
  items: (MenuItem & { id?: string })[],
  rootCode: string,
): Set<string> {
  const result = new Set<string>([rootCode])
  let grew = true
  while (grew) {
    grew = false
    for (const item of items) {
      if (!item.code || result.has(item.code)) continue
      if (item.parentCode && result.has(item.parentCode)) {
        result.add(item.code)
        grew = true
      }
    }
  }
  return result
}

const emptyForm = (parentCode: string, order: number) => ({
  name: '',
  code: '',
  menuTextEn: '',
  menuTextTr: '',
  parentCode,
  icon: '',
  shortName: '',
  order,
  url: '',
  isDisabled: false,
})

export function MenuAddDialog({
  isOpen,
  onClose,
  initialParentCode,
  initialOrder,
  rawItems,
  editMenu,
  onSaved,
}: MenuAddDialogProps) {
  const isEditMode = !!editMenu?.id
  const [form, setForm] = useState(() => emptyForm(initialParentCode, initialOrder))
  const [saving, setSaving] = useState(false)
  const { translate } = useLocalization()

  useEffect(() => {
    if (!isOpen) return
    if (editMenu?.id) {
      setForm({
        name: editMenu.code ?? '',
        code: editMenu.code ?? '',
        menuTextEn: editMenu.menuTextEn ?? '',
        menuTextTr: editMenu.menuTextTr ?? '',
        parentCode: editMenu.parentCode ?? '',
        icon: editMenu.icon ?? '',
        shortName: editMenu.shortName ?? '',
        order: editMenu.order ?? 0,
        url: editMenu.url ?? '',
        isDisabled: editMenu.isDisabled ?? false,
      })
      return
    }
    setForm(emptyForm(initialParentCode, initialOrder))
  }, [isOpen, initialParentCode, initialOrder, editMenu])

  // Kök menülerde kısa ad zorunlu; alt menülerde isteğe bağlıdır.
  const shortNameRequired = !form.parentCode.trim()

  // Düzenlenen menü, kendisi veya alt ağacındaki bir menünün altına taşınamaz.
  const parentOptions = useMemo(() => {
    if (!isEditMode) return []
    const blocked = collectDescendantCodes(rawItems, editMenu?.code ?? '')
    return rawItems
      .filter((item) => item.code && !blocked.has(item.code))
      .map((item) => ({ code: item.code!, label: item.code! }))
      .sort((a, b) => a.label.localeCompare(b.label))
  }, [isEditMode, rawItems, editMenu])

  const handleSave = async () => {
    if (!form.code.trim() || !form.menuTextEn.trim()) return
    if (shortNameRequired && !form.shortName.trim()) return
    setSaving(true)
    try {
      const savedMenu = {
        code: form.code.trim(),
        // Görünen ad dil anahtarıdır; menü kodu ile aynı kalır.
        displayName: form.code.trim(),
        parentCode: form.parentCode.trim() || undefined,
        icon: form.icon || undefined,
        shortName: form.shortName.trim() || undefined,
        order: form.order,
        isDisabled: form.isDisabled,
        url: form.url.trim() || undefined,
        menuTextTr: form.menuTextTr.trim(),
        menuTextEn: form.menuTextEn.trim(),
      } as MenuDto

      if (isEditMode) {
        // Kod ve görünen ad dışındaki tüm alanlar güncellenir; sunucu kodu korur.
        await menuService.updateWithLanguageKeyText(editMenu!.id!, {
          ...(editMenu as MenuDto),
          ...savedMenu,
        })
      } else {
        await menuService.createWithLanguageKeyText(savedMenu)
      }

      await onSaved({
        code: savedMenu.code!,
        parentCode: savedMenu.parentCode,
        menuTextEn: savedMenu.menuTextEn!,
        menuTextTr: savedMenu.menuTextTr!,
        icon: savedMenu.icon,
        shortName: savedMenu.shortName,
      })
      onClose()
    } catch (e: any) {
      toast.push(<Notification title={e.message} type="danger" />, {
        placement: 'bottom-end',
      })
    } finally {
      setSaving(false)
    }
  }

  const fieldCls =
    'h-9 px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-sm text-gray-700 dark:text-gray-200 outline-none focus:border-indigo-400 w-full'
  const disabledCls =
    'h-9 px-3 py-2 rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700 text-sm text-gray-400 dark:text-gray-500 cursor-not-allowed w-full'
  const labelCls = 'text-xs font-medium text-gray-500 dark:text-gray-400 mb-1'

  const toCodeToken = (value: string) => value.replace(/\s+/g, '')
  const toSpacedLabel = (value: string) =>
    value
      .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
      .replace(/([A-Z])([A-Z][a-z])/g, '$1 $2')
      .trim()

  return (
    <Dialog isOpen={isOpen} onClose={onClose} onRequestClose={onClose} width={680}>
      <div className="flex flex-col gap-5 p-1">
        {/* Header */}
        <div className="flex items-center gap-2 pb-1 border-b border-gray-100 dark:border-gray-700">
          {isEditMode ? (
            <FaEdit className="text-indigo-500 text-sm" />
          ) : (
            <FaPlus className="text-green-500 text-sm" />
          )}
          <h5 className="text-base font-semibold text-gray-800 dark:text-gray-100">
            {isEditMode
              ? translate('::App.Platform.EditMenu')
              : translate('::App.Platform.AddNewMenu')}
          </h5>
        </div>

        {/* Row 1 — Name | Code */}
        <div className="grid grid-cols-2 gap-4">
          <div className="flex flex-col">
            <label className={labelCls}>
              {translate('::App.Listform.ListformField.Name')}{' '}
              <span className="text-red-500">*</span>
            </label>
            {/* Ad, kodu ve dil anahtarını türetir; düzenlemede kod sabit olduğu için kilitlidir. */}
            <Input
              unstyle
              autoFocus={!isEditMode}
              disabled={isEditMode}
              value={form.name}
              onChange={(e) => {
                const codeToken = toCodeToken(e.target.value)
                const spacedLabel = toSpacedLabel(codeToken)

                setForm((p) => ({
                  ...p,
                  name: codeToken,
                  code: `App.Wizard.${codeToken}`,
                  menuTextEn: spacedLabel,
                  menuTextTr: spacedLabel,
                  shortName: codeToken.substring(0, 3),
                }))
              }}
              placeholder="MyMenu"
              className={isEditMode ? disabledCls : fieldCls}
            />
          </div>
          <div className="flex flex-col">
            <label className={labelCls}>
              {translate('::App.Platform.Code')} <span className="text-red-500">*</span>
            </label>
            <Input
              unstyle
              value={form.code}
              disabled
              placeholder="App.Wizard.MyMenu"
              className={disabledCls}
            />
          </div>
        </div>

        {/* Row 2 — Icon (full width) */}
        <div className="flex flex-col">
          <label className={labelCls}>
            {translate('::App.Listform.ListformField.Icon')} <span className="text-red-500">*</span>
          </label>
          <IconPickerField
            value={form.icon}
            onChange={(key) => setForm((p) => ({ ...p, icon: key }))}
          />
        </div>

        {/* Row 3 — Display Name EN | Display Name TR */}
        <div className="grid grid-cols-2 gap-4">
          <div className="flex flex-col">
            <label className={labelCls}>
              {translate('::App.Platform.DisplayNameEnglish')}{' '}
              <span className="text-red-500">*</span>
            </label>
            <Input
              unstyle
              value={form.menuTextEn}
              onChange={(e) => setForm((p) => ({ ...p, menuTextEn: e.target.value }))}
              placeholder="My Menu"
              className={fieldCls}
            />
          </div>
          <div className="flex flex-col">
            <label className={labelCls}>
              {translate('::App.Platform.DisplayNameTurkish')}{' '}
              <span className="text-red-500">*</span>
            </label>
            <Input
              unstyle
              value={form.menuTextTr}
              onChange={(e) => setForm((p) => ({ ...p, menuTextTr: e.target.value }))}
              placeholder={translate('::App.Menu.NamePlaceholder')}
              className={fieldCls}
            />
          </div>
        </div>

        {/* Row 4 — Menu Parent | Order */}
        <div className="grid grid-cols-2 gap-4">
          <div className="flex flex-col">
            <label className={labelCls}>{translate('::App.Platform.MenuParent')}</label>
            {isEditMode ? (
              <select
                value={form.parentCode}
                onChange={(e) => setForm((p) => ({ ...p, parentCode: e.target.value }))}
                className={fieldCls}
              >
                <option value="">{translate('::App.WizardStep1.RootMenu')}</option>
                {parentOptions.map((option) => (
                  <option key={option.code} value={option.code}>
                    {option.label}
                  </option>
                ))}
              </select>
            ) : (
              <Input unstyle disabled value={form.parentCode} className={disabledCls} />
            )}
          </div>
          <div className="flex flex-col">
            <label className={labelCls}>{translate('::App.Listform.ListformField.Order')}</label>
            <Input
              unstyle
              type="number"
              value={form.order}
              onChange={(e) => setForm((p) => ({ ...p, order: Number(e.target.value) }))}
              className={fieldCls}
            />
          </div>
        </div>

        {/* Row 5 — Short Name (full width) */}
        <div className="flex flex-col">
          <label className={labelCls}>
            {translate('::App.WizardStep1.ShortName')}
            {shortNameRequired ? (
              <span className="text-red-500 ml-0.5">*</span>
            ) : (
              <span className="ml-1 text-gray-400 font-normal">
                ({translate('::App.WizardStep1.Optional')})
              </span>
            )}
          </label>
          <Input
            unstyle
            value={form.shortName}
            onChange={(e) => setForm((p) => ({ ...p, shortName: e.target.value }))}
            placeholder="Sas, Finance, Hr…"
            className={`${fieldCls}`}
          />
          {shortNameRequired && (
            <p className="text-xs text-gray-400 mt-1">{translate('::App.Platform.MenuCodeHint')}</p>
          )}
        </div>

        {/* Row 6 — Url | Durum (yalnızca düzenlemede) */}
        {isEditMode && (
          <div className="grid grid-cols-2 gap-4">
            <div className="flex flex-col">
              <label className={labelCls}>{translate('::App.Platform.OpenUrl')}</label>
              <Input
                unstyle
                value={form.url}
                onChange={(e) => setForm((p) => ({ ...p, url: e.target.value }))}
                placeholder="/admin/list/App.Wizard.MyMenu"
                className={`${fieldCls} font-mono`}
              />
            </div>
            <div className="flex flex-col">
              <label className={labelCls}>{translate('::App.Platform.Status')}</label>
              <label className="flex h-9 cursor-pointer items-center gap-2">
                <Input
                  unstyle
                  type="checkbox"
                  checked={!form.isDisabled}
                  onChange={(e) => setForm((p) => ({ ...p, isDisabled: !e.target.checked }))}
                  className="h-4 w-4 accent-indigo-500"
                />
                <span className="text-sm text-gray-700 dark:text-gray-200">
                  {translate(
                    form.isDisabled
                      ? '::App.Platform.Passive'
                      : '::App.Listform.ListformField.IsActive',
                  )}
                </span>
              </label>
            </div>
          </div>
        )}

        {/* Footer */}
        <div className="flex justify-end gap-2 pt-1 border-t border-gray-100 dark:border-gray-700">
          <Button type="button" size="sm" variant="plain" onClick={onClose}>
            {translate('::App.Platform.Cancel')}
          </Button>
          <Button
            type="button"
            size="sm"
            variant="solid"
            loading={saving}
            disabled={
              !form.code.trim() ||
              !form.menuTextEn.trim() ||
              !form.menuTextTr.trim() ||
              !form.icon.trim() ||
              (shortNameRequired && !form.shortName.trim())
            }
            onClick={handleSave}
          >
            {translate('::App.Platform.Save')}
          </Button>
        </div>
      </div>
    </Dialog>
  )
}
