import React, { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  TrashIcon, PlusIcon, PencilIcon, TagIcon, MapPinIcon,
  BuildingOffice2Icon, HeartIcon, ShieldCheckIcon, WrenchScrewdriverIcon,
  CheckCircleIcon, XCircleIcon, PhotoIcon, XMarkIcon,
} from '@heroicons/react/24/outline';
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { toast } from 'sonner';
import { api } from '../lib/api';
import type { ApiResponse, PaginatedResponse } from '../lib/api';
import type { Category, CategoryBundle, Representation } from '../types';
import { useAuthStore } from '../stores/authStore';
import PageHeader from '../components/ui/PageHeader';
import DataTable, { Column } from '../components/ui/DataTable';
import ConfirmDialog from '../components/ui/ConfirmDialog';
import Modal from '../components/ui/Modal';
import SearchableSelect from '../components/ui/SearchableSelect';

// ── Tab config ──────────────────────────────────────────────────────────────

interface TabConfig {
  key: CategoryBundle;
  label: string;
  icon: React.ElementType;
  color: string;
  description: string;
  hasParent: boolean;
  parentBundle?: CategoryBundle;
  parentLabel?: string;
  hasLogo: boolean;
  hasCityFields: boolean;
  hasWeight: boolean;
}

const TABS: TabConfig[] = [
  {
    key: 'state',
    label: 'استان‌ها',
    icon: MapPinIcon,
    color: 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-400/10',
    description: 'مدیریت استان‌ها',
    hasParent: false, hasLogo: false, hasCityFields: false, hasWeight: true,
  },
  {
    key: 'city',
    label: 'شهرها',
    icon: BuildingOffice2Icon,
    color: 'text-indigo-600 dark:text-indigo-400 bg-indigo-50 dark:bg-indigo-400/10',
    description: 'مدیریت شهرها و اطلاعات تفصیلی هر شهر',
    hasParent: true, parentBundle: 'state', parentLabel: 'استان',
    hasLogo: false, hasCityFields: true, hasWeight: true,
  },
  {
    key: 'specially_doctor',
    label: 'تخصص‌های پزشکی',
    icon: HeartIcon,
    color: 'text-rose-600 dark:text-rose-400 bg-rose-50 dark:bg-rose-400/10',
    description: 'تخصص‌ها و زیرتخصص‌های پزشکی',
    hasParent: true, parentBundle: 'specially_doctor', parentLabel: 'تخصص والد',
    hasLogo: false, hasCityFields: false, hasWeight: true,
  },
  {
    key: 'doctor_services',
    label: 'خدمات پزشک',
    icon: WrenchScrewdriverIcon,
    color: 'text-orange-600 dark:text-orange-400 bg-orange-50 dark:bg-orange-400/10',
    description: 'خدمات قابل ارائه توسط پزشکان',
    hasParent: false, hasLogo: false, hasCityFields: false, hasWeight: true,
  },
  {
    key: 'insurance_type',
    label: 'بیمه پایه',
    icon: ShieldCheckIcon,
    color: 'text-teal-600 dark:text-teal-400 bg-teal-50 dark:bg-teal-400/10',
    description: 'انواع بیمه‌های پایه درمانی',
    hasParent: false, hasLogo: true, hasCityFields: false, hasWeight: false,
  },
  {
    key: 'supplementary_insurance',
    label: 'بیمه تکمیلی',
    icon: ShieldCheckIcon,
    color: 'text-cyan-600 dark:text-cyan-400 bg-cyan-50 dark:bg-cyan-400/10',
    description: 'انواع بیمه‌های تکمیلی درمانی',
    hasParent: false, hasLogo: true, hasCityFields: false, hasWeight: false,
  },
  {
    key: 'tag',
    label: 'تگ‌های بلاگ',
    icon: TagIcon,
    color: 'text-violet-600 dark:text-violet-400 bg-violet-50 dark:bg-violet-400/10',
    description: 'تگ‌های مورد استفاده در مطالب بلاگ',
    hasParent: false, hasLogo: false, hasCityFields: false, hasWeight: true,
  },
];

// ── Zod schema ──────────────────────────────────────────────────────────────

const baseSchema = z.object({
  label:              z.string().min(1, 'نام الزامی است'),
  status:             z.string().optional(),
  weight:             z.string().optional(),
  parent_id:          z.number().nullable().optional(),
  representation_id:  z.number().nullable().optional(),
  title:              z.string().optional(),
  contact_phone:      z.string().optional(),
  email:              z.string().optional(),
  description:        z.string().optional(),
  slogan:             z.string().optional(),
  domain:             z.string().optional(),
  keywords:           z.string().optional(),
  footer_description: z.string().optional(),
  footer_disclaimer:  z.string().optional(),
});
type FormData = z.infer<typeof baseSchema>;

// ── Logo uploader ────────────────────────────────────────────────────────────

function LogoUploadField({
  value,
  onChange,
}: {
  value: string | null;
  onChange: (url: string | null) => void;
}) {
  const [uploading, setUploading] = useState(false);
  const token = useAuthStore((s) => s.token);

  const handleFile = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    setUploading(true);
    try {
      const res = await fetch('/api/v1/admin/category/upload-logo', {
        method: 'POST',
        headers: {
          'Content-Disposition': `attachment; filename="${file.name}"`,
          'Content-Type': 'application/octet-stream',
          ...(token ? { Authorization: `Bearer ${token}` } : {}),
        },
        body: file,
      });
      const json = await res.json();
      if (json.success) {
        onChange(json.data.url);
        toast.success('لگو آپلود شد');
      } else {
        toast.error(json.errors?.[0]?.message ?? 'خطا در آپلود');
      }
    } catch {
      toast.error('خطا در آپلود تصویر');
    } finally {
      setUploading(false);
      e.target.value = '';
    }
  };

  return (
    <div className="flex items-center gap-3">
      {value ? (
        <div className="relative group">
          <img
            src={value}
            alt="logo"
            className="w-16 h-16 object-contain rounded-xl border border-slate-200 dark:border-gray-600 bg-white dark:bg-gray-800 p-1"
          />
          <button
            type="button"
            onClick={() => onChange(null)}
            className="absolute -top-1.5 -right-1.5 w-5 h-5 bg-red-500 hover:bg-red-600 rounded-full text-white flex items-center justify-center shadow transition-colors"
          >
            <XMarkIcon className="w-3 h-3" />
          </button>
        </div>
      ) : (
        <div className="w-16 h-16 rounded-xl border-2 border-dashed border-slate-300 dark:border-gray-600 flex items-center justify-center bg-slate-50 dark:bg-gray-800">
          <PhotoIcon className="w-6 h-6 text-slate-300 dark:text-gray-600" />
        </div>
      )}

      <label className={`cursor-pointer cp-btn-secondary text-sm ${uploading ? 'opacity-60 pointer-events-none' : ''}`}>
        {uploading ? (
          <span className="flex items-center gap-2">
            <svg className="w-4 h-4 animate-spin" viewBox="0 0 24 24" fill="none">
              <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
              <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z" />
            </svg>
            در حال آپلود...
          </span>
        ) : (
          <span className="flex items-center gap-2">
            <PhotoIcon className="w-4 h-4" />
            {value ? 'تغییر لگو' : 'انتخاب لگو'}
          </span>
        )}
        <input
          type="file"
          accept="image/jpeg,image/png,image/webp"
          className="hidden"
          onChange={handleFile}
          disabled={uploading}
        />
      </label>
      <p className="text-xs text-slate-400 dark:text-slate-500">JPG، PNG یا WebP — حداکثر ۵ مگابایت</p>
    </div>
  );
}

// ── Helper to load parent list ──────────────────────────────────────────────

function useBundleList(bundle: CategoryBundle | undefined) {
  return useQuery({
    queryKey: ['categories', bundle],
    queryFn: () => api.get<ApiResponse<{ data: Category[] }>>(`/api/v1/categorys/${bundle}`),
    enabled: !!bundle,
    staleTime: 60_000,
  });
}

// ── Dynamic form fields ─────────────────────────────────────────────────────

interface FormFieldsProps {
  register: ReturnType<typeof useForm<FormData>>['register'];
  control: ReturnType<typeof useForm<FormData>>['control'];
  errors: ReturnType<typeof useForm<FormData>>['formState']['errors'];
  tab: TabConfig;
  parentOptions: { value: number; label: string }[];
  representationOptions: { value: number; label: string }[];
  parentLoading: boolean;
  representationLoading: boolean;
  logoUrl: string | null;
  onLogoChange: (url: string | null) => void;
}

function CategoryFormFields({
  register, control, errors, tab,
  parentOptions, representationOptions,
  parentLoading, representationLoading,
  logoUrl, onLogoChange,
}: FormFieldsProps) {
  return (
    <div className="space-y-4">
      {/* Logo upload (insurance bundles) */}
      {tab.hasLogo && (
        <div>
          <label className="cp-label">لگو</label>
          <LogoUploadField value={logoUrl} onChange={onLogoChange} />
        </div>
      )}

      {/* Label */}
      <div>
        <label className="cp-label">نام <span className="text-red-500">*</span></label>
        <input {...register('label')} className="cp-input h-11" placeholder="نام دسته‌بندی" />
        {errors.label && <p className="text-red-500 text-xs mt-1">{errors.label.message}</p>}
      </div>

      {/* Parent selector */}
      {tab.hasParent && (
        <div>
          <label className="cp-label">{tab.parentLabel}</label>
          <Controller
            name="parent_id"
            control={control}
            render={({ field }) => (
              <SearchableSelect
                options={parentOptions}
                value={field.value ?? null}
                onChange={(val) => field.onChange(val as number | null)}
                placeholder="-- بدون والد --"
                isClearable
                isLoading={parentLoading}
                noOptionsMessage="موردی یافت نشد"
              />
            )}
          />
        </div>
      )}

      {/* Representation selector (city only) */}
      {tab.key === 'city' && (
        <div>
          <label className="cp-label">نماینده</label>
          <Controller
            name="representation_id"
            control={control}
            render={({ field }) => (
              <SearchableSelect
                options={representationOptions}
                value={field.value ?? null}
                onChange={(val) => field.onChange(val as number | null)}
                placeholder="انتخاب نماینده..."
                isClearable
                isLoading={representationLoading}
                noOptionsMessage="هیچ نماینده‌ای یافت نشد"
              />
            )}
          />
        </div>
      )}

      {/* Title (city) */}
      {tab.key === 'city' && (
        <div>
          <label className="cp-label">عنوان صفحه</label>
          <input {...register('title')} className="cp-input h-11" placeholder="عنوان نمایشی" />
        </div>
      )}

      {/* City-specific fields */}
      {tab.hasCityFields && (
        <>
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="cp-label">تلفن تماس</label>
              <input {...register('contact_phone')} className="cp-input h-10" dir="ltr" placeholder="021xxxxxxxx" />
            </div>
            <div>
              <label className="cp-label">ایمیل</label>
              <input {...register('email')} type="email" className="cp-input h-10" dir="ltr" placeholder="city@example.com" />
            </div>
          </div>
          <div>
            <label className="cp-label">دامنه</label>
            <input {...register('domain')} className="cp-input h-10" dir="ltr" placeholder="city.example.com" />
          </div>
          <div>
            <label className="cp-label">شعار (slogan)</label>
            <input {...register('slogan')} className="cp-input h-10" placeholder="شعار شهر" />
          </div>
          <div>
            <label className="cp-label">کلیدواژه‌ها</label>
            <input {...register('keywords')} className="cp-input h-10" placeholder="کلیدواژه، کلیدواژه، ..." />
          </div>
          <div>
            <label className="cp-label">توضیحات</label>
            <textarea {...register('description')} rows={3} className="cp-textarea" placeholder="توضیحات شهر" />
          </div>
          <div>
            <label className="cp-label">توضیحات فوتر</label>
            <textarea {...register('footer_description')} rows={2} className="cp-textarea" placeholder="متن فوتر شهر" />
          </div>
          <div>
            <label className="cp-label">سلب مسئولیت فوتر</label>
            <textarea {...register('footer_disclaimer')} rows={2} className="cp-textarea" placeholder="متن سلب مسئولیت" />
          </div>
        </>
      )}

      {/* Weight */}
      {tab.hasWeight && (
        <div>
          <label className="cp-label">ترتیب نمایش (weight)</label>
          <input {...register('weight')} type="number" dir="ltr" className="cp-input h-11 w-32" placeholder="0" />
        </div>
      )}

      {/* Status */}
      <div>
        <label className="cp-label">وضعیت</label>
        <Controller
          name="status"
          control={control}
          render={({ field }) => (
            <SearchableSelect
              options={[
                { value: '1', label: 'فعال' },
                { value: '0', label: 'غیرفعال' },
              ]}
              value={field.value ?? '1'}
              onChange={(val) => field.onChange(val ?? '1')}
              isClearable={false}
            />
          )}
        />
      </div>
    </div>
  );
}

// ── Main Page ───────────────────────────────────────────────────────────────

export default function CategoriesPage() {
  const qc = useQueryClient();
  const [activeTab, setActiveTab]         = useState<CategoryBundle>('state');
  const [search, setSearch]               = useState('');
  const [addOpen, setAddOpen]             = useState(false);
  const [editTarget, setEditTarget]       = useState<Category | null>(null);
  const [deleteTarget, setDeleteTarget]   = useState<Category | null>(null);
  const [logoUrl, setLogoUrl]             = useState<string | null>(null);

  const tab = TABS.find((t) => t.key === activeTab)!;

  // Main list
  const { data, isLoading } = useQuery({
    queryKey: ['categories', activeTab],
    queryFn: () => api.get<ApiResponse<{ data: Category[] }>>(`/api/v1/categorys/${activeTab}`),
  });

  // Parent list (state for city, specially_doctor for sub-specialties)
  const parentBundle = tab.hasParent ? tab.parentBundle : undefined;
  const parentQuery  = useBundleList(parentBundle);
  const parentRaw: Category[] = (parentQuery.data?.data as any)?.data
    ?? parentQuery.data?.data?.data
    ?? [];
  const parentOptions = parentRaw.map((p) => ({ value: p.id, label: p.label }));

  // Build parent ID → label map for table display
  const parentMap = React.useMemo(
    () => Object.fromEntries(parentRaw.map((p) => [p.id, p.label])),
    [parentRaw],
  );

  // Representations list (only needed for city tab)
  const representationsQuery = useQuery({
    queryKey: ['representations', 'for-select'],
    queryFn: () =>
      api.get<PaginatedResponse<Representation>>('/api/v1/admin/representations?limit=200'),
    enabled: activeTab === 'city',
    staleTime: 2 * 60_000,
  });
  const representationOptions = (representationsQuery.data?.data ?? []).map((r) => ({
    value: r.id,
    label: r.full_name + (r.mobile_number ? ` — ${r.mobile_number}` : ''),
  }));
  const representationMap = React.useMemo(
    () => Object.fromEntries(
      (representationsQuery.data?.data ?? []).map((r) => [r.id, r.full_name])
    ),
    [representationsQuery.data],
  );

  const { register, handleSubmit, reset, control, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(baseSchema),
    defaultValues: { status: '1', weight: '0' },
  });

  const closeAdd = () => {
    setAddOpen(false);
    setLogoUrl(null);
    reset({ status: '1', weight: '0' });
  };

  const closeEdit = () => {
    setEditTarget(null);
    setLogoUrl(null);
    reset({ status: '1', weight: '0' });
  };

  const createMutation = useMutation({
    mutationFn: (d: FormData) =>
      api.post<ApiResponse<Category>>('/api/v1/category', buildPayload(d, activeTab, logoUrl)),
    onSuccess: () => {
      toast.success('دسته‌بندی اضافه شد');
      closeAdd();
      qc.invalidateQueries({ queryKey: ['categories', activeTab] });
    },
    onError: (err: Error) => toast.error(err.message),
  });

  const updateMutation = useMutation({
    mutationFn: ({ id, d }: { id: number; d: FormData }) =>
      api.patch<ApiResponse<Category>>(`/api/v1/category/${id}`, buildPayload(d, activeTab, logoUrl)),
    onSuccess: () => {
      toast.success('دسته‌بندی بروزرسانی شد');
      closeEdit();
      qc.invalidateQueries({ queryKey: ['categories', activeTab] });
    },
    onError: (err: Error) => toast.error(err.message),
  });

  const deleteMutation = useMutation({
    mutationFn: (c: Category) => api.delete<ApiResponse<null>>(`/api/v1/category/${c.id}`),
    onSuccess: () => {
      toast.success('دسته‌بندی حذف شد');
      setDeleteTarget(null);
      qc.invalidateQueries({ queryKey: ['categories', activeTab] });
    },
    onError: (err: Error) => toast.error(err.message),
  });

  const openEdit = (c: Category) => {
    setEditTarget(c);
    setLogoUrl(c.logo_url ?? null);
    reset({
      label:              c.label ?? '',
      status:             String(c.status ?? 1),
      weight:             String(c.weight ?? 0),
      parent_id:          c.parent_id ?? null,
      representation_id:  c.representation_id ?? null,
      title:              c.title ?? '',
      contact_phone:      c.contact_phone ?? '',
      email:              c.email ?? '',
      description:        c.description ?? '',
      slogan:             c.slogan ?? '',
      domain:             c.domain ?? '',
      keywords:           c.keywords ?? '',
      footer_description: c.footer_description ?? '',
      footer_disclaimer:  c.footer_disclaimer ?? '',
    });
  };

  const handleTabChange = (key: CategoryBundle) => {
    setActiveTab(key);
    setSearch('');
  };

  const allItems: Category[] = (data?.data as any)?.data ?? (data?.data as any) ?? [];
  const filtered = search
    ? allItems.filter((c) => (c.label ?? '').toLowerCase().includes(search.toLowerCase()))
    : allItems;

  // ── Per-bundle columns ──────────────────────────────────────────────────
  const baseColumns: Column<Category>[] = [
    {
      key: 'id',
      header: 'شناسه',
      className: 'w-16',
      render: (c) => <span className="text-xs text-slate-400 dark:text-slate-500 font-mono">{c.id}</span>,
    },
    {
      key: 'label',
      header: 'نام',
      render: (c) => (
        <div className="flex items-center gap-2.5">
          {tab.hasLogo && c.logo_url && (
            <img src={c.logo_url} alt={c.label ?? ''} className="w-8 h-8 object-contain rounded-lg border border-slate-200 dark:border-gray-600 bg-white dark:bg-gray-800 p-0.5 shrink-0" />
          )}
          {tab.hasLogo && !c.logo_url && (
            <div className="w-8 h-8 rounded-lg border border-dashed border-slate-200 dark:border-gray-600 flex items-center justify-center shrink-0">
              <PhotoIcon className="w-4 h-4 text-slate-300 dark:text-gray-600" />
            </div>
          )}
          <div>
            <span className="font-medium text-slate-800 dark:text-slate-100">{c.label}</span>
            {c.title && c.title !== c.label && (
              <p className="text-xs text-slate-400 dark:text-slate-500 truncate max-w-[160px]">{c.title}</p>
            )}
          </div>
        </div>
      ),
    },
  ];

  const parentCol: Column<Category> = {
    key: 'parent_id',
    header: tab.parentLabel ?? 'والد',
    render: (c) => c.parent_id
      ? <span className="text-xs bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 px-2 py-0.5 rounded-full">{parentMap[c.parent_id] ?? `#${c.parent_id}`}</span>
      : <span className="text-slate-300 dark:text-slate-600">—</span>,
  };

  const representationCol: Column<Category> = {
    key: 'representation_id',
    header: 'نماینده',
    render: (c) => c.representation_id
      ? <span className="text-xs text-slate-600 dark:text-slate-300">{representationMap[c.representation_id] ?? `#${c.representation_id}`}</span>
      : <span className="text-slate-300 dark:text-slate-600">—</span>,
  };

  const cityExtraCols: Column<Category>[] = [
    {
      key: 'domain',
      header: 'دامنه',
      render: (c) => c.domain
        ? <span className="text-xs font-mono text-slate-500 dark:text-slate-400">{c.domain}</span>
        : <span className="text-slate-300 dark:text-slate-600">—</span>,
    },
    {
      key: 'contact_phone',
      header: 'تلفن',
      render: (c) => c.contact_phone
        ? <span className="text-xs font-mono" dir="ltr">{c.contact_phone}</span>
        : <span className="text-slate-300 dark:text-slate-600">—</span>,
    },
  ];

  const weightCol: Column<Category> = {
    key: 'weight',
    header: 'ترتیب',
    className: 'w-20',
    render: (c) => <span className="text-xs text-slate-400 dark:text-slate-500">{c.weight}</span>,
  };

  const statusCol: Column<Category> = {
    key: 'status',
    header: 'وضعیت',
    className: 'w-24',
    render: (c) => c.status === 1
      ? (
        <span className="inline-flex items-center gap-1 text-xs font-medium text-green-700 dark:text-green-400 bg-green-50 dark:bg-green-400/10 px-2 py-0.5 rounded-full">
          <CheckCircleIcon className="w-3 h-3" /> فعال
        </span>
      ) : (
        <span className="inline-flex items-center gap-1 text-xs font-medium text-slate-500 dark:text-slate-400 bg-slate-100 dark:bg-slate-400/10 px-2 py-0.5 rounded-full">
          <XCircleIcon className="w-3 h-3" /> غیرفعال
        </span>
      ),
  };

  let columns: Column<Category>[] = [...baseColumns];
  if (tab.hasParent)      columns = [...columns, parentCol];
  if (tab.key === 'city') columns = [...columns, representationCol, ...cityExtraCols];
  if (tab.hasWeight)      columns = [...columns, weightCol];
  columns = [...columns, statusCol];

  const modalSize = tab.hasCityFields ? 'lg' : 'sm';
  const formSharedProps = {
    register, control, errors, tab,
    parentOptions,
    representationOptions,
    parentLoading: parentQuery.isLoading,
    representationLoading: representationsQuery.isLoading,
    logoUrl,
    onLogoChange: setLogoUrl,
  };

  return (
    <div>
      <PageHeader
        title="دسته‌بندی‌ها"
        description={tab.description}
        breadcrumbs={[{ label: 'داشبورد', to: '/admin/dashboard' }, { label: 'دسته‌بندی‌ها' }]}
        action={
          <button onClick={() => { reset({ status: '1', weight: '0' }); setLogoUrl(null); setAddOpen(true); }} className="cp-btn-primary">
            <PlusIcon className="w-4 h-4" />
            افزودن {tab.label.slice(0, -1) || tab.label}
          </button>
        }
      />

      <div className="cp-card overflow-hidden">
        {/* ── Tab bar ── */}
        <div className="flex overflow-x-auto border-b border-slate-200 dark:border-gray-700 px-2 pt-2 gap-1 scrollbar-none">
          {TABS.map((t) => {
            const Icon = t.icon;
            const isActive = t.key === activeTab;
            return (
              <button
                key={t.key}
                onClick={() => handleTabChange(t.key)}
                className={`flex items-center gap-2 px-3.5 py-2.5 text-sm font-medium rounded-t-xl whitespace-nowrap border-b-2 -mb-px transition-all ${
                  isActive
                    ? 'border-primary-600 text-primary-600 dark:text-primary-400 bg-primary-50/50 dark:bg-primary-400/5'
                    : 'border-transparent text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-slate-50 dark:hover:bg-gray-800/50'
                }`}
              >
                <Icon className="w-4 h-4 shrink-0" />
                {t.label}
                <span className={`text-[10px] font-semibold px-1.5 py-0.5 rounded-full transition-colors ${
                  isActive
                    ? 'bg-primary-100 dark:bg-primary-400/20 text-primary-700 dark:text-primary-300'
                    : 'bg-slate-100 dark:bg-gray-700 text-slate-500 dark:text-slate-400'
                }`}>
                  {isLoading ? '…' : allItems.length}
                </span>
              </button>
            );
          })}
        </div>

        {/* ── Bundle info bar ── */}
        <div className="flex items-center gap-3 px-6 py-3 border-b border-slate-100 dark:border-gray-700/50 bg-slate-50/50 dark:bg-gray-800/30">
          <div className={`w-7 h-7 rounded-lg flex items-center justify-center ${tab.color.split(' ').slice(0, 2).join(' ')} bg-opacity-10`}>
            <tab.icon className={`w-4 h-4 ${tab.color.split(' ')[0]}`} />
          </div>
          <div>
            <p className="text-xs font-medium text-slate-700 dark:text-slate-300">{tab.label}</p>
            <p className="text-[11px] text-slate-400 dark:text-slate-500">{tab.description}</p>
          </div>
          <div className="mr-auto flex items-center gap-2 text-xs text-slate-500 dark:text-slate-400">
            <span className="font-mono bg-slate-100 dark:bg-gray-700 px-2 py-0.5 rounded text-[11px]">{activeTab}</span>
            {!isLoading && <span>{allItems.length} مورد</span>}
          </div>
        </div>

        {/* ── Table ── */}
        <div className="p-5">
          <DataTable<Category>
            columns={columns}
            data={filtered}
            loading={isLoading}
            searchValue={search}
            onSearchChange={setSearch}
            searchPlaceholder={`جستجو در ${tab.label}...`}
            emptyMessage={`هیچ ${tab.label.slice(0, -1) || tab.label}ی یافت نشد`}
            actions={(cat) => (
              <>
                <button onClick={() => openEdit(cat)} className="cp-action-edit" title="ویرایش">
                  <PencilIcon className="w-4 h-4" />
                </button>
                <button onClick={() => setDeleteTarget(cat)} className="cp-action-delete" title="حذف">
                  <TrashIcon className="w-4 h-4" />
                </button>
              </>
            )}
          />
        </div>
      </div>

      {/* ── Add Modal ── */}
      <Modal
        open={addOpen}
        title={`افزودن — ${tab.label}`}
        size={modalSize}
        onClose={closeAdd}
        footer={
          <>
            <button onClick={closeAdd} className="cp-btn-secondary">لغو</button>
            <button form="cat-add-form" type="submit" disabled={createMutation.isPending} className="cp-btn-primary">
              {createMutation.isPending ? 'در حال ذخیره...' : 'افزودن'}
            </button>
          </>
        }
      >
        <form id="cat-add-form" onSubmit={handleSubmit((d) => createMutation.mutate(d))}>
          <CategoryFormFields {...formSharedProps} />
        </form>
      </Modal>

      {/* ── Edit Modal ── */}
      <Modal
        open={!!editTarget}
        title={`ویرایش — ${editTarget?.label ?? ''}`}
        size={modalSize}
        onClose={closeEdit}
        footer={
          <>
            <button onClick={closeEdit} className="cp-btn-secondary">لغو</button>
            <button form="cat-edit-form" type="submit" disabled={updateMutation.isPending} className="cp-btn-primary">
              {updateMutation.isPending ? 'در حال ذخیره...' : 'ذخیره'}
            </button>
          </>
        }
      >
        <form
          id="cat-edit-form"
          onSubmit={handleSubmit((d) => editTarget && updateMutation.mutate({ id: editTarget.id, d }))}
        >
          <CategoryFormFields {...formSharedProps} />
        </form>
      </Modal>

      <ConfirmDialog
        open={!!deleteTarget}
        title="حذف دسته‌بندی"
        message={`آیا از حذف "${deleteTarget?.label}" اطمینان دارید؟ این عمل قابل بازگشت نیست.`}
        confirmLabel="حذف"
        danger
        loading={deleteMutation.isPending}
        onConfirm={() => deleteTarget && deleteMutation.mutate(deleteTarget)}
        onCancel={() => setDeleteTarget(null)}
      />
    </div>
  );
}

// ── Build API payload from form data ───────────────────────────────────────

function buildPayload(d: FormData, bundle: CategoryBundle, logoUrl: string | null): Record<string, unknown> {
  const base: Record<string, unknown> = {
    label:  d.label.trim(),
    bundle,
    status: d.status !== undefined ? parseInt(d.status) : 1,
  };

  if (d.weight !== undefined && d.weight !== '') base.weight = parseInt(d.weight);
  if (d.parent_id != null)         base.parent_id         = d.parent_id;
  if (d.title?.trim())             base.title             = d.title.trim();

  if (bundle === 'insurance_type' || bundle === 'supplementary_insurance') {
    base.logo_url = logoUrl;
  }

  if (bundle === 'city') {
    base.representation_id = d.representation_id ?? null;
    if (d.contact_phone?.trim())      base.contact_phone      = d.contact_phone.trim();
    if (d.email?.trim())              base.email              = d.email.trim();
    if (d.description?.trim())        base.description        = d.description.trim();
    if (d.slogan?.trim())             base.slogan             = d.slogan.trim();
    if (d.domain?.trim())             base.domain             = d.domain.trim();
    if (d.keywords?.trim())           base.keywords           = d.keywords.trim();
    if (d.footer_description?.trim()) base.footer_description = d.footer_description.trim();
    if (d.footer_disclaimer?.trim())  base.footer_disclaimer  = d.footer_disclaimer.trim();
  }

  return base;
}
