import { useState, useMemo, type ReactNode } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import {
  Plus, Loader2, Trash2, Archive, RotateCcw, Edit2, Package,
  Search, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight,
  TrendingDown, Layers, Printer, AlertTriangle, X, Clock, LayoutGrid, TableProperties, Columns,
} from 'lucide-react';
import { api } from '../api/client';
import type { InventorySpool, SpoolAssignment } from '../api/client';
import { Button } from '../components/Button';
import { SpoolFormModal } from '../components/SpoolFormModal';
import { ColumnConfigModal, type ColumnConfig } from '../components/ColumnConfigModal';
import { useToast } from '../contexts/ToastContext';

type ArchiveFilter = 'active' | 'archived';
type UsageFilter = 'all' | 'used' | 'new';
type ViewMode = 'table' | 'cards';

// Column definitions for the inventory table
const COLUMN_CONFIG_KEY = 'bambuddy-inventory-columns';

const DEFAULT_COLUMNS: ColumnConfig[] = [
  { id: 'id', label: '#', visible: true },
  { id: 'added_time', label: 'Added', visible: true },
  { id: 'encode_time', label: 'Encoded', visible: false },
  { id: 'last_used_time', label: 'Last Used', visible: false },
  { id: 'rgba', label: 'Color', visible: true },
  { id: 'material', label: 'Material', visible: true },
  { id: 'subtype', label: 'Subtype', visible: true },
  { id: 'color_name', label: 'Color Name', visible: false },
  { id: 'brand', label: 'Brand', visible: true },
  { id: 'slicer_filament', label: 'Slicer Filament', visible: false },
  { id: 'location', label: 'Location', visible: true },
  { id: 'label_weight', label: 'Label', visible: true },
  { id: 'net', label: 'Net', visible: true },
  { id: 'gross', label: 'Gross', visible: false },
  { id: 'added_full', label: 'Full', visible: false },
  { id: 'used', label: 'Used', visible: false },
  { id: 'printed_total', label: 'Printed Total', visible: false },
  { id: 'printed_since_weight', label: 'Printed Since Weight', visible: false },
  { id: 'note', label: 'Note', visible: false },
  { id: 'pa_k', label: 'PA(K)', visible: true },
  { id: 'tag_id', label: 'Tag ID', visible: false },
  { id: 'data_origin', label: 'Data Origin', visible: false },
  { id: 'tag_type', label: 'Linked Tag Type', visible: false },
  { id: 'remaining', label: 'Remaining', visible: true },
];

function loadColumnConfig(): ColumnConfig[] {
  try {
    const stored = localStorage.getItem(COLUMN_CONFIG_KEY);
    if (stored) {
      const parsed = JSON.parse(stored) as ColumnConfig[];
      const defaultIds = new Set(DEFAULT_COLUMNS.map((c) => c.id));
      const storedIds = new Set(parsed.map((c) => c.id));
      // Keep stored columns that still exist in defaults
      const validStored = parsed.filter((c) => defaultIds.has(c.id));
      // Add any new default columns not in stored config
      const newColumns = DEFAULT_COLUMNS.filter((c) => !storedIds.has(c.id));
      return [...validStored, ...newColumns];
    }
  } catch {
    // Ignore errors
  }
  return DEFAULT_COLUMNS.map((c) => ({ ...c }));
}

function saveColumnConfig(config: ColumnConfig[]) {
  try {
    localStorage.setItem(COLUMN_CONFIG_KEY, JSON.stringify(config));
  } catch {
    // Ignore errors
  }
}

function formatWeight(g: number, useKg = false): string {
  if (useKg && g >= 1000) return `${(g / 1000).toFixed(1)}kg`;
  return `${Math.round(g)}g`;
}

// Material color mapping for pills
const MATERIAL_COLORS: Record<string, string> = {
  PLA: 'bg-green-500/20 text-green-400',
  ABS: 'bg-red-500/20 text-red-400',
  PETG: 'bg-blue-500/20 text-blue-400',
  TPU: 'bg-purple-500/20 text-purple-400',
  ASA: 'bg-orange-500/20 text-orange-400',
  PA: 'bg-yellow-500/20 text-yellow-400',
  PC: 'bg-cyan-500/20 text-cyan-400',
  PET: 'bg-sky-500/20 text-sky-400',
};

type TFn = (key: string) => string;

function formatDate(dateStr: string | null): string {
  if (!dateStr) return '-';
  const date = new Date(dateStr);
  return date.toLocaleDateString('en-GB', { day: '2-digit', month: '2-digit', year: '2-digit' });
}

type CellCtx = {
  spool: InventorySpool;
  remaining: number;
  pct: number;
  assignmentMap: Record<number, SpoolAssignment>;
};

// Column header labels (25 columns — matching SpoolBuddy exactly)
const columnHeaders: Record<string, (t: TFn) => string> = {
  id: () => '#',
  added_time: () => 'Added',
  encode_time: () => 'Encoded',
  last_used_time: () => 'Last Used',
  rgba: (t) => t('inventory.color'),
  material: (t) => t('inventory.material'),
  subtype: (t) => t('inventory.subtype'),
  color_name: (t) => t('inventory.colorName'),
  brand: (t) => t('inventory.brand'),
  slicer_filament: (t) => t('inventory.slicerFilament'),
  location: () => 'Location',
  label_weight: (t) => t('inventory.labelWeight'),
  net: (t) => t('inventory.net'),
  gross: () => 'Gross',
  added_full: () => 'Full',
  used: (t) => t('inventory.weightUsed'),
  printed_total: () => 'Printed Total',
  printed_since_weight: () => 'Printed Since Weight',
  note: (t) => t('inventory.note'),
  pa_k: () => 'PA(K)',
  tag_id: () => 'Tag ID',
  data_origin: () => 'Data Origin',
  tag_type: () => 'Linked Tag Type',
  remaining: (t) => t('inventory.remaining'),
};

// Column cell renderers (25 columns — matching SpoolBuddy exactly)
const columnCells: Record<string, (ctx: CellCtx) => ReactNode> = {
  id: ({ spool }) => (
    <span className="text-sm font-medium text-white">{spool.id}</span>
  ),
  added_time: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{formatDate(spool.created_at)}</span>
  ),
  encode_time: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{formatDate(spool.encode_time)}</span>
  ),
  last_used_time: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.last_used ? formatDate(spool.last_used) : 'Never'}</span>
  ),
  rgba: ({ spool }) => (
    <div className="flex items-center gap-2">
      <span
        className="w-5 h-5 rounded-full border border-white/20 flex-shrink-0"
        style={{ backgroundColor: spool.rgba ? `#${spool.rgba.substring(0, 6)}` : '#808080' }}
      />
      <span className="text-sm text-white">{spool.color_name || '-'}</span>
    </div>
  ),
  material: ({ spool }) => (
    <span className="text-sm text-white">{spool.material}</span>
  ),
  subtype: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.subtype || '-'}</span>
  ),
  color_name: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.color_name || '-'}</span>
  ),
  brand: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.brand || '-'}</span>
  ),
  slicer_filament: ({ spool }) => (
    <span className="text-sm text-bambu-gray" title={spool.slicer_filament || undefined}>
      {spool.slicer_filament_name || spool.slicer_filament || '-'}
    </span>
  ),
  location: ({ spool, assignmentMap }) => {
    const assignment = assignmentMap[spool.id];
    if (!assignment) return <span className="text-sm text-bambu-gray">-</span>;
    return (
      <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-purple-500/20 text-purple-400">
        AMS {assignment.ams_id} T{assignment.tray_id}
      </span>
    );
  },
  label_weight: ({ spool }) => (
    <span className="text-sm text-white">{formatWeight(spool.label_weight)}</span>
  ),
  net: ({ remaining }) => (
    <span className="text-sm text-white">{formatWeight(remaining)}</span>
  ),
  gross: ({ spool, remaining }) => (
    <span className="text-sm text-bambu-gray">{formatWeight(remaining + spool.core_weight)}</span>
  ),
  added_full: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.added_full == null ? '-' : spool.added_full ? 'Yes' : 'No'}</span>
  ),
  used: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.weight_used > 0 ? formatWeight(spool.weight_used) : '-'}</span>
  ),
  printed_total: () => (
    <span className="text-sm text-bambu-gray/50">-</span>
  ),
  printed_since_weight: () => (
    <span className="text-sm text-bambu-gray/50">-</span>
  ),
  note: ({ spool }) => (
    <span className="text-sm text-bambu-gray max-w-[150px] truncate block" title={spool.note || undefined}>{spool.note || '-'}</span>
  ),
  pa_k: ({ spool }) => {
    const count = spool.k_profiles?.length ?? 0;
    if (count === 0) return <span className="text-sm text-bambu-gray">-</span>;
    return (
      <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-bambu-green/20 text-bambu-green">
        K
      </span>
    );
  },
  tag_id: ({ spool }) => {
    const tag = spool.tag_uid || spool.tray_uuid;
    if (!tag) return <span className="text-sm text-bambu-gray/50">-</span>;
    return (
      <span className="text-sm text-bambu-gray font-mono" title={tag}>
        {tag.length > 12 ? `${tag.slice(0, 6)}...${tag.slice(-4)}` : tag}
      </span>
    );
  },
  data_origin: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.data_origin || '-'}</span>
  ),
  tag_type: ({ spool }) => (
    <span className="text-sm text-bambu-gray">{spool.tag_type || '-'}</span>
  ),
  remaining: ({ remaining, pct }) => (
    <div className="flex items-center gap-2">
      <div className="flex-1 h-2 bg-bambu-dark-tertiary rounded-full overflow-hidden">
        <div
          className={`h-full rounded-full ${pct > 50 ? 'bg-bambu-green' : pct > 20 ? 'bg-yellow-500' : 'bg-red-500'}`}
          style={{ width: `${Math.min(pct, 100)}%` }}
        />
      </div>
      <span className="text-xs text-bambu-gray min-w-[40px] text-right">{Math.round(remaining)}g</span>
    </div>
  ),
};

export default function InventoryPage() {
  const { t } = useTranslation();
  const queryClient = useQueryClient();
  const { showToast } = useToast();
  const [formModal, setFormModal] = useState<{ spool?: InventorySpool | null } | null>(null);

  // Filter state
  const [archiveFilter, setArchiveFilter] = useState<ArchiveFilter>('active');
  const [usageFilter, setUsageFilter] = useState<UsageFilter>('all');
  const [materialFilter, setMaterialFilter] = useState('');
  const [brandFilter, setBrandFilter] = useState('');
  const [search, setSearch] = useState('');
  const [viewMode, setViewMode] = useState<ViewMode>('table');
  const [columnConfig, setColumnConfig] = useState<ColumnConfig[]>(loadColumnConfig);
  const [showColumnModal, setShowColumnModal] = useState(false);

  // Pagination state
  const [pageIndex, setPageIndex] = useState(0);
  const [pageSize, setPageSize] = useState(15);

  const { data: spools, isLoading } = useQuery({
    queryKey: ['inventory-spools'],
    queryFn: () => api.getSpools(true), // Always fetch all, filter client-side
  });

  const { data: assignments } = useQuery({
    queryKey: ['spool-assignments'],
    queryFn: () => api.getAssignments(),
  });

  const deleteMutation = useMutation({
    mutationFn: (id: number) => api.deleteSpool(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['inventory-spools'] });
      showToast(t('inventory.spoolDeleted'), 'success');
    },
  });

  const archiveMutation = useMutation({
    mutationFn: (id: number) => api.archiveSpool(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['inventory-spools'] });
      showToast(t('inventory.spoolArchived'), 'success');
    },
  });

  const restoreMutation = useMutation({
    mutationFn: (id: number) => api.restoreSpool(id),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['inventory-spools'] });
      showToast(t('inventory.spoolRestored'), 'success');
    },
  });

  // Stats calculation (active spools only)
  const stats = useMemo(() => {
    if (!spools) return null;
    let totalWeight = 0;
    let totalConsumed = 0;
    let lowStock = 0;
    let activeCount = 0;
    const byMaterial: Record<string, { count: number; weight: number }> = {};
    for (const s of spools) {
      if (s.archived_at) continue;
      activeCount++;
      const remaining = Math.max(0, s.label_weight - s.weight_used);
      totalWeight += remaining;
      totalConsumed += s.weight_used;
      const pct = s.label_weight > 0 ? (remaining / s.label_weight) * 100 : 0;
      if (pct < 20) lowStock++;
      const mat = s.material || 'Unknown';
      if (!byMaterial[mat]) byMaterial[mat] = { count: 0, weight: 0 };
      byMaterial[mat].count++;
      byMaterial[mat].weight += remaining;
    }
    return { totalWeight, totalConsumed, lowStock, byMaterial, totalSpools: activeCount };
  }, [spools]);

  const inPrinterCount = assignments?.length ?? 0;

  // Map spool_id -> assignment for location column
  const assignmentMap = useMemo(() => {
    const map: Record<number, SpoolAssignment> = {};
    for (const a of assignments || []) {
      map[a.spool_id] = a;
    }
    return map;
  }, [assignments]);

  // Top materials by weight for stat card pills
  const topMaterials = useMemo(() => {
    if (!stats) return [];
    return Object.entries(stats.byMaterial)
      .sort((a, b) => b[1].weight - a[1].weight)
      .slice(0, 4);
  }, [stats]);

  // Filtering pipeline
  const filteredSpools = useMemo(() => {
    let filtered = spools || [];

    // Archive filter
    if (archiveFilter === 'active') {
      filtered = filtered.filter((s) => !s.archived_at);
    } else {
      filtered = filtered.filter((s) => !!s.archived_at);
    }

    // Usage filter
    if (usageFilter === 'used') {
      filtered = filtered.filter((s) => s.weight_used > 0);
    } else if (usageFilter === 'new') {
      filtered = filtered.filter((s) => s.weight_used === 0);
    }

    // Material dropdown
    if (materialFilter) {
      filtered = filtered.filter((s) => s.material === materialFilter);
    }

    // Brand dropdown
    if (brandFilter) {
      filtered = filtered.filter((s) => s.brand === brandFilter);
    }

    // Global search
    if (search) {
      const q = search.toLowerCase();
      filtered = filtered.filter((s) =>
        s.brand?.toLowerCase().includes(q) ||
        s.material.toLowerCase().includes(q) ||
        s.color_name?.toLowerCase().includes(q) ||
        s.subtype?.toLowerCase().includes(q) ||
        s.note?.toLowerCase().includes(q) ||
        s.slicer_filament_name?.toLowerCase().includes(q)
      );
    }

    return filtered;
  }, [spools, archiveFilter, usageFilter, materialFilter, brandFilter, search]);

  // Pagination
  const totalPages = Math.max(1, Math.ceil(filteredSpools.length / pageSize));
  const safePageIndex = Math.min(pageIndex, totalPages - 1);
  const pagedSpools = filteredSpools.slice(safePageIndex * pageSize, (safePageIndex + 1) * pageSize);

  // Reset page on filter changes
  const resetPage = () => setPageIndex(0);

  // Unique values for filter dropdowns
  const uniqueMaterials = [...new Set(spools?.map((s) => s.material) || [])].sort();
  const uniqueBrands = [...new Set(spools?.map((s) => s.brand).filter(Boolean) || [])].sort() as string[];

  // Check if any filters are non-default
  const hasActiveFilters = archiveFilter !== 'active' || usageFilter !== 'all' || !!materialFilter || !!brandFilter || !!search;

  const handleColumnConfigSave = (config: ColumnConfig[]) => {
    setColumnConfig(config);
    saveColumnConfig(config);
  };

  // Visible column IDs in order
  const visibleColumns = useMemo(
    () => columnConfig.filter((c) => c.visible).map((c) => c.id),
    [columnConfig]
  );

  const clearAllFilters = () => {
    setArchiveFilter('active');
    setUsageFilter('all');
    setMaterialFilter('');
    setBrandFilter('');
    setSearch('');
    resetPage();
  };

  return (
    <div className="p-4 md:p-6 space-y-6">
      {/* Header */}
      <div className="flex items-center justify-between">
        <div>
          <div className="flex items-center gap-3">
            <Package className="w-6 h-6 text-bambu-green" />
            <h1 className="text-2xl font-bold text-white">{t('inventory.title')}</h1>
          </div>
          <p className="text-sm text-bambu-gray mt-1 ml-9">{t('inventory.noSpools').split('.')[0] ? '' : ''}</p>
        </div>
        <Button onClick={() => setFormModal({ spool: null })}>
          <Plus className="w-4 h-4" />
          {t('inventory.addSpool')}
        </Button>
      </div>

      {/* Stats Bar */}
      {stats && !isLoading && (
        <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-3">
          {/* Total Inventory */}
          <div className="bg-bambu-dark-secondary rounded-lg p-4">
            <div className="flex items-center gap-2 mb-1">
              <Package className="w-4 h-4 text-bambu-green" />
              <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.totalInventory')}</span>
            </div>
            <div className="text-xl font-bold text-white">{formatWeight(stats.totalWeight, true)}</div>
            <div className="text-xs text-bambu-gray mt-1">{stats.totalSpools} {stats.totalSpools !== 1 ? t('inventory.spools') : t('inventory.spool')}</div>
          </div>

          {/* Total Consumed */}
          <div className="bg-bambu-dark-secondary rounded-lg p-4">
            <div className="flex items-center gap-2 mb-1">
              <TrendingDown className="w-4 h-4 text-blue-400" />
              <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.totalConsumed')}</span>
            </div>
            <div className="text-xl font-bold text-white">{formatWeight(stats.totalConsumed, true)}</div>
            <div className="text-xs text-bambu-gray mt-1">{t('inventory.sinceTracking')}</div>
          </div>

          {/* By Material */}
          <div className="bg-bambu-dark-secondary rounded-lg p-4">
            <div className="flex items-center gap-2 mb-1">
              <Layers className="w-4 h-4 text-green-400" />
              <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.byMaterial')}</span>
            </div>
            <div className="flex flex-wrap gap-1.5 mt-1">
              {topMaterials.map(([mat, data]) => (
                <span
                  key={mat}
                  className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium ${MATERIAL_COLORS[mat] || 'bg-bambu-dark-tertiary text-bambu-gray'}`}
                >
                  {mat} <span className="opacity-70">{formatWeight(data.weight, true)}</span>
                </span>
              ))}
            </div>
          </div>

          {/* In Printer */}
          <div className="bg-bambu-dark-secondary rounded-lg p-4">
            <div className="flex items-center gap-2 mb-1">
              <Printer className="w-4 h-4 text-purple-400" />
              <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.inPrinter')}</span>
            </div>
            <div className="text-xl font-bold text-white">{inPrinterCount}</div>
            <div className="text-xs text-bambu-gray mt-1">{t('inventory.loadedInAms')}</div>
          </div>

          {/* Low Stock */}
          <div className="bg-bambu-dark-secondary rounded-lg p-4">
            <div className="flex items-center gap-2 mb-1">
              <AlertTriangle className="w-4 h-4 text-yellow-400" />
              <span className="text-xs text-bambu-gray font-medium uppercase tracking-wide">{t('inventory.lowStock')}</span>
            </div>
            <div className={`text-xl font-bold ${stats.lowStock > 0 ? 'text-yellow-400' : 'text-white'}`}>{stats.lowStock}</div>
            <div className="text-xs text-bambu-gray mt-1">{t('inventory.lowStockThreshold')}</div>
          </div>
        </div>
      )}

      {/* Toolbar: Search + View toggle */}
      <div className="flex flex-col sm:flex-row gap-3 items-start sm:items-center justify-between">
        <div className="relative flex-1 max-w-md">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-bambu-gray/50" />
          <input
            type="text"
            value={search}
            onChange={(e) => { setSearch(e.target.value); resetPage(); }}
            placeholder={t('inventory.search')}
            className="w-full pl-10 pr-8 py-2 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded-lg text-white text-sm placeholder:text-bambu-gray/50 focus:outline-none focus:border-bambu-green"
          />
          {search && (
            <button
              onClick={() => { setSearch(''); resetPage(); }}
              className="absolute right-3 top-1/2 -translate-y-1/2 text-bambu-gray hover:text-white"
            >
              <X className="w-4 h-4" />
            </button>
          )}
        </div>

        <div className="flex items-center gap-2">
          {/* Columns button */}
          <button
            onClick={() => setShowColumnModal(true)}
            className="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-bambu-gray border border-bambu-dark-tertiary rounded-lg hover:bg-bambu-dark-tertiary transition-colors"
            title={t('inventory.configureColumns')}
          >
            <Columns className="w-4 h-4" />
            <span className="hidden sm:inline">{t('inventory.columns')}</span>
          </button>
          {/* Table / Cards toggle */}
          <div className="flex bg-bambu-dark-primary border border-bambu-dark-tertiary rounded-lg overflow-hidden">
            <button
              onClick={() => setViewMode('table')}
              className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium transition-colors ${
                viewMode === 'table'
                  ? 'bg-bambu-green text-white'
                  : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
              }`}
            >
              <TableProperties className="w-4 h-4" />
              <span className="hidden sm:inline">{t('inventory.table')}</span>
            </button>
            <button
              onClick={() => setViewMode('cards')}
              className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium transition-colors ${
                viewMode === 'cards'
                  ? 'bg-bambu-green text-white'
                  : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
              }`}
            >
              <LayoutGrid className="w-4 h-4" />
              <span className="hidden sm:inline">{t('inventory.cards')}</span>
            </button>
          </div>
        </div>
      </div>

      {/* Filter chips row */}
      <div className="flex flex-wrap items-center gap-2">
        {/* Active / Archived chips */}
        <div className="flex items-center rounded-lg border border-bambu-dark-tertiary overflow-hidden">
          <button
            onClick={() => { setArchiveFilter('active'); resetPage(); }}
            className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium transition-colors ${
              archiveFilter === 'active'
                ? 'bg-bambu-green/20 text-bambu-green'
                : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
            }`}
          >
            <Package className="w-3.5 h-3.5" />
            {t('inventory.active')}
          </button>
          <button
            onClick={() => { setArchiveFilter('archived'); resetPage(); }}
            className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium transition-colors ${
              archiveFilter === 'archived'
                ? 'bg-bambu-green/20 text-bambu-green'
                : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
            }`}
          >
            <Archive className="w-3.5 h-3.5" />
            {t('inventory.archived')}
          </button>
        </div>

        <div className="w-px h-5 bg-bambu-dark-tertiary" />

        {/* All / Used / New chips */}
        <div className="flex items-center rounded-lg border border-bambu-dark-tertiary overflow-hidden">
          <button
            onClick={() => { setUsageFilter('all'); resetPage(); }}
            className={`px-3 py-1.5 text-xs font-medium transition-colors ${
              usageFilter === 'all'
                ? 'bg-bambu-green/20 text-bambu-green'
                : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
            }`}
          >
            {t('inventory.all')}
          </button>
          <button
            onClick={() => { setUsageFilter('used'); resetPage(); }}
            className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium transition-colors ${
              usageFilter === 'used'
                ? 'bg-bambu-green/20 text-bambu-green'
                : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
            }`}
          >
            <Clock className="w-3.5 h-3.5" />
            {t('inventory.used')}
          </button>
          <button
            onClick={() => { setUsageFilter('new'); resetPage(); }}
            className={`px-3 py-1.5 text-xs font-medium transition-colors ${
              usageFilter === 'new'
                ? 'bg-bambu-green/20 text-bambu-green'
                : 'text-bambu-gray hover:bg-bambu-dark-tertiary'
            }`}
          >
            {t('inventory.new')}
          </button>
        </div>

        <div className="w-px h-5 bg-bambu-dark-tertiary" />

        {/* Material dropdown chip */}
        <select
          value={materialFilter}
          onChange={(e) => { setMaterialFilter(e.target.value); resetPage(); }}
          className={`px-3 py-1.5 rounded-lg border text-xs font-medium transition-colors cursor-pointer focus:outline-none ${
            materialFilter
              ? 'bg-bambu-green/20 text-bambu-green border-bambu-green/30'
              : 'bg-transparent text-bambu-gray border-bambu-dark-tertiary hover:bg-bambu-dark-tertiary'
          }`}
        >
          <option value="">{t('inventory.material')}</option>
          {uniqueMaterials.map((m) => (
            <option key={m} value={m}>{m}</option>
          ))}
        </select>

        {/* Brand dropdown chip */}
        <select
          value={brandFilter}
          onChange={(e) => { setBrandFilter(e.target.value); resetPage(); }}
          className={`px-3 py-1.5 rounded-lg border text-xs font-medium transition-colors cursor-pointer focus:outline-none ${
            brandFilter
              ? 'bg-bambu-green/20 text-bambu-green border-bambu-green/30'
              : 'bg-transparent text-bambu-gray border-bambu-dark-tertiary hover:bg-bambu-dark-tertiary'
          }`}
        >
          <option value="">{t('inventory.brand')}</option>
          {uniqueBrands.map((b) => (
            <option key={b} value={b}>{b}</option>
          ))}
        </select>

        {/* Clear filters */}
        {hasActiveFilters && (
          <>
            <div className="w-px h-5 bg-bambu-dark-tertiary" />
            <button
              onClick={clearAllFilters}
              className="flex items-center gap-1 text-xs text-bambu-gray hover:text-bambu-green transition-colors"
            >
              <X className="w-3.5 h-3.5" />
              {t('inventory.clearFilters')}
            </button>
          </>
        )}

        {/* Results count */}
        <span className="ml-auto text-xs text-bambu-gray">
          {filteredSpools.length} {filteredSpools.length !== 1 ? t('inventory.spools') : t('inventory.spool')}
        </span>
      </div>

      {/* Content */}
      {isLoading ? (
        <div className="flex justify-center py-16">
          <Loader2 className="w-8 h-8 text-bambu-green animate-spin" />
        </div>
      ) : viewMode === 'cards' ? (
        /* Cards view */
        pagedSpools.length > 0 ? (
          <>
            <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
              {pagedSpools.map((spool) => {
                const remaining = Math.max(0, spool.label_weight - spool.weight_used);
                const pct = spool.label_weight > 0 ? (remaining / spool.label_weight) * 100 : 0;
                const colorStyle = spool.rgba ? `#${spool.rgba.substring(0, 6)}` : '#808080';
                return (
                  <div
                    key={spool.id}
                    className={`bg-bambu-dark-secondary rounded-lg overflow-hidden border border-bambu-dark-tertiary hover:border-bambu-green transition-colors cursor-pointer ${spool.archived_at ? 'opacity-50' : ''}`}
                    onClick={() => setFormModal({ spool })}
                  >
                    {/* Color header */}
                    <div className="h-14 flex items-center justify-center" style={{ backgroundColor: colorStyle }}>
                      <span className="bg-white/90 text-gray-800 px-3 py-0.5 rounded-full text-sm font-medium">
                        {spool.color_name || '-'}
                      </span>
                    </div>
                    {/* Content */}
                    <div className="p-4 space-y-3">
                      <div className="flex items-start justify-between gap-2">
                        <div>
                          <h3 className="font-semibold text-white">{spool.material}{spool.subtype ? ` ${spool.subtype}` : ''}</h3>
                          <p className="text-sm text-bambu-gray">{spool.brand || '-'}</p>
                        </div>
                        <span className="text-xs font-mono text-bambu-gray bg-bambu-dark-tertiary px-2 py-1 rounded">#{spool.id}</span>
                      </div>
                      {/* Progress */}
                      <div>
                        <div className="flex justify-between text-xs text-bambu-gray mb-1">
                          <span>{t('inventory.remaining')}</span>
                          <span>{Math.round(pct)}%</span>
                        </div>
                        <div className="flex items-center gap-2">
                          <div className="flex-1 h-2 bg-bambu-dark-tertiary rounded-full overflow-hidden">
                            <div
                              className={`h-full rounded-full ${pct > 50 ? 'bg-bambu-green' : pct > 20 ? 'bg-yellow-500' : 'bg-red-500'}`}
                              style={{ width: `${Math.min(pct, 100)}%` }}
                            />
                          </div>
                          <span className="text-xs text-bambu-gray min-w-[40px] text-right">{Math.round(remaining)}g</span>
                        </div>
                      </div>
                      {/* Weight info */}
                      <div className="grid grid-cols-2 gap-2 text-xs">
                        <div>
                          <span className="text-bambu-gray/60">{t('inventory.labelWeight')}: </span>
                          <span className="text-bambu-gray">{formatWeight(spool.label_weight)}</span>
                        </div>
                        <div>
                          <span className="text-bambu-gray/60">{t('inventory.weightUsed')}: </span>
                          <span className="text-bambu-gray">{spool.weight_used > 0 ? formatWeight(spool.weight_used) : '-'}</span>
                        </div>
                      </div>
                      {/* Note */}
                      {spool.note && (
                        <div className="text-xs text-bambu-gray/60 pt-2 border-t border-bambu-dark-tertiary truncate" title={spool.note}>
                          {spool.note}
                        </div>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
            {/* Pagination for cards */}
            <PaginationBar
              pageIndex={safePageIndex}
              pageSize={pageSize}
              totalRows={filteredSpools.length}
              totalPages={totalPages}
              onPageChange={setPageIndex}
              onPageSizeChange={(size) => { setPageSize(size); resetPage(); }}
              t={t}
            />
          </>
        ) : (
          <EmptyFilterState
            hasFilters={hasActiveFilters}
            onAddSpool={() => setFormModal({ spool: null })}
            t={t}
          />
        )
      ) : (
        /* Table view */
        pagedSpools.length > 0 ? (
          <div className="bg-bambu-dark-secondary rounded-lg overflow-hidden border border-bambu-dark-tertiary">
            <div className="overflow-x-auto">
              <table className="w-full">
                <thead>
                  <tr className="border-b border-bambu-dark-tertiary bg-bambu-dark-tertiary/30">
                    {visibleColumns.map((colId) => (
                      <th
                        key={colId}
                        className={`text-left py-3 px-4 text-xs font-medium text-bambu-gray uppercase tracking-wide ${colId === 'remaining' ? 'min-w-[150px]' : ''}`}
                      >
                        {columnHeaders[colId]?.(t) ?? colId}
                      </th>
                    ))}
                    <th className="text-right py-3 px-4 text-xs font-medium text-bambu-gray uppercase tracking-wide">{t('common.actions')}</th>
                  </tr>
                </thead>
                <tbody>
                  {pagedSpools.map((spool) => {
                    const remaining = Math.max(0, spool.label_weight - spool.weight_used);
                    const pct = spool.label_weight > 0 ? (remaining / spool.label_weight) * 100 : 0;
                    return (
                      <tr
                        key={spool.id}
                        className={`border-b border-bambu-dark-tertiary/50 hover:bg-bambu-dark-tertiary/30 transition-colors cursor-pointer ${
                          spool.archived_at ? 'opacity-50' : ''
                        }`}
                        onClick={() => setFormModal({ spool })}
                      >
                        {visibleColumns.map((colId) => (
                          <td key={colId} className="py-3 px-4">
                            {columnCells[colId]?.({ spool, remaining, pct, assignmentMap })}
                          </td>
                        ))}
                        <td className="py-3 px-4">
                          <div className="flex items-center justify-end gap-1" onClick={(e) => e.stopPropagation()}>
                            <button
                              onClick={() => setFormModal({ spool })}
                              className="p-1.5 text-bambu-gray hover:text-white rounded transition-colors"
                              title={t('inventory.editSpool')}
                            >
                              <Edit2 className="w-4 h-4" />
                            </button>
                            {spool.archived_at ? (
                              <button
                                onClick={() => restoreMutation.mutate(spool.id)}
                                className="p-1.5 text-bambu-gray hover:text-bambu-green rounded transition-colors"
                                title={t('inventory.restore')}
                              >
                                <RotateCcw className="w-4 h-4" />
                              </button>
                            ) : (
                              <button
                                onClick={() => archiveMutation.mutate(spool.id)}
                                className="p-1.5 text-bambu-gray hover:text-yellow-400 rounded transition-colors"
                                title={t('inventory.archive')}
                              >
                                <Archive className="w-4 h-4" />
                              </button>
                            )}
                            <button
                              onClick={() => {
                                if (confirm(t('inventory.deleteConfirm'))) {
                                  deleteMutation.mutate(spool.id);
                                }
                              }}
                              className="p-1.5 text-bambu-gray hover:text-red-400 rounded transition-colors"
                              title={t('common.delete')}
                            >
                              <Trash2 className="w-4 h-4" />
                            </button>
                          </div>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>

            {/* Pagination inside card footer */}
            <div className="flex items-center justify-between px-4 py-3 bg-bambu-dark-tertiary/50 border-t border-bambu-dark-tertiary text-sm">
              <span className="text-bambu-gray">
                {t('inventory.showing')} {safePageIndex * pageSize + 1} {t('inventory.to')}{' '}
                {Math.min((safePageIndex + 1) * pageSize, filteredSpools.length)}{' '}
                {t('inventory.of')} {filteredSpools.length} {t('inventory.spools')}
              </span>

              <div className="flex items-center gap-2">
                <span className="text-bambu-gray">{t('inventory.show')}</span>
                <select
                  value={pageSize}
                  onChange={(e) => { setPageSize(Number(e.target.value)); resetPage(); }}
                  className="px-2 py-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:outline-none focus:border-bambu-green"
                >
                  {[15, 30, 50, 100].map((n) => (
                    <option key={n} value={n}>{n}</option>
                  ))}
                </select>

                <button
                  onClick={() => setPageIndex(0)}
                  disabled={safePageIndex === 0}
                  className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
                  title="First page"
                >
                  <ChevronsLeft className="w-4 h-4" />
                </button>
                <button
                  onClick={() => setPageIndex((p) => Math.max(0, p - 1))}
                  disabled={safePageIndex === 0}
                  className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
                >
                  <ChevronLeft className="w-4 h-4" />
                </button>
                <span className="text-bambu-gray px-2 whitespace-nowrap">
                  {t('inventory.page')} {safePageIndex + 1} {t('inventory.of')} {totalPages}
                </span>
                <button
                  onClick={() => setPageIndex((p) => Math.min(totalPages - 1, p + 1))}
                  disabled={safePageIndex >= totalPages - 1}
                  className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
                >
                  <ChevronRight className="w-4 h-4" />
                </button>
                <button
                  onClick={() => setPageIndex(totalPages - 1)}
                  disabled={safePageIndex >= totalPages - 1}
                  className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
                  title="Last page"
                >
                  <ChevronsRight className="w-4 h-4" />
                </button>
              </div>
            </div>
          </div>
        ) : (
          <EmptyFilterState
            hasFilters={hasActiveFilters}
            onAddSpool={() => setFormModal({ spool: null })}
            t={t}
          />
        )
      )}

      {/* Spool Form Modal */}
      {formModal !== null && (
        <SpoolFormModal
          isOpen={true}
          onClose={() => setFormModal(null)}
          spool={formModal.spool}
        />
      )}

      {/* Column Config Modal */}
      <ColumnConfigModal
        isOpen={showColumnModal}
        onClose={() => setShowColumnModal(false)}
        columns={columnConfig}
        defaultColumns={DEFAULT_COLUMNS}
        onSave={handleColumnConfigSave}
      />
    </div>
  );
}

/* Pagination bar (reused for cards view) */
function PaginationBar({
  pageIndex, pageSize, totalRows, totalPages, onPageChange, onPageSizeChange, t,
}: {
  pageIndex: number;
  pageSize: number;
  totalRows: number;
  totalPages: number;
  onPageChange: (page: number) => void;
  onPageSizeChange: (size: number) => void;
  t: (key: string) => string;
}) {
  if (totalPages <= 1) return null;
  return (
    <div className="flex items-center justify-between pt-2 text-sm">
      <span className="text-bambu-gray">
        {t('inventory.showing')} {pageIndex * pageSize + 1} {t('inventory.to')}{' '}
        {Math.min((pageIndex + 1) * pageSize, totalRows)}{' '}
        {t('inventory.of')} {totalRows} {t('inventory.spools')}
      </span>
      <div className="flex items-center gap-2">
        <span className="text-bambu-gray">{t('inventory.show')}</span>
        <select
          value={pageSize}
          onChange={(e) => onPageSizeChange(Number(e.target.value))}
          className="px-2 py-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded text-white text-sm focus:outline-none focus:border-bambu-green"
        >
          {[15, 30, 50, 100].map((n) => (
            <option key={n} value={n}>{n}</option>
          ))}
        </select>
        <button
          onClick={() => onPageChange(0)}
          disabled={pageIndex === 0}
          className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
        >
          <ChevronsLeft className="w-4 h-4" />
        </button>
        <button
          onClick={() => onPageChange(Math.max(0, pageIndex - 1))}
          disabled={pageIndex === 0}
          className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
        >
          <ChevronLeft className="w-4 h-4" />
        </button>
        <span className="text-bambu-gray px-2 whitespace-nowrap">
          {t('inventory.page')} {pageIndex + 1} {t('inventory.of')} {totalPages}
        </span>
        <button
          onClick={() => onPageChange(Math.min(totalPages - 1, pageIndex + 1))}
          disabled={pageIndex >= totalPages - 1}
          className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
        >
          <ChevronRight className="w-4 h-4" />
        </button>
        <button
          onClick={() => onPageChange(totalPages - 1)}
          disabled={pageIndex >= totalPages - 1}
          className="p-1.5 rounded text-bambu-gray hover:text-white disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
        >
          <ChevronsRight className="w-4 h-4" />
        </button>
      </div>
    </div>
  );
}

/* Empty state matching SpoolBuddy's design */
function EmptyFilterState({
  hasFilters,
  onAddSpool,
  t,
}: {
  hasFilters: boolean;
  onAddSpool: () => void;
  t: (key: string) => string;
}) {
  return (
    <div className="flex flex-col items-center justify-center py-16 px-4">
      <div className="relative mb-6">
        <div className="absolute inset-0 -m-4 bg-bambu-green/5 rounded-full blur-2xl" />
        <div className="relative flex items-center justify-center w-24 h-24 rounded-2xl bg-gradient-to-br from-bambu-dark-secondary to-bambu-dark-tertiary border border-bambu-dark-tertiary shadow-lg">
          <div className="absolute -top-1 -right-1 w-3 h-3 rounded-full bg-bambu-green/30" />
          <div className="absolute -bottom-2 -left-2 w-2 h-2 rounded-full bg-bambu-green/20" />
          {hasFilters ? (
            <Search className="w-10 h-10 text-bambu-gray/40" strokeWidth={1.5} />
          ) : (
            <div className="relative">
              <div className="w-14 h-14 rounded-full border-4 border-bambu-gray/20 flex items-center justify-center">
                <div className="w-6 h-6 rounded-full bg-bambu-gray/10 border-2 border-bambu-gray/20" />
              </div>
              <div className="absolute -bottom-1 -right-1 w-6 h-6 rounded-full bg-bambu-green flex items-center justify-center shadow-md">
                <span className="text-white text-lg font-bold leading-none">+</span>
              </div>
            </div>
          )}
        </div>
      </div>
      <h3 className="text-lg font-semibold text-white mb-2 text-center">
        {hasFilters ? t('inventory.noSpoolsMatch') : t('inventory.noSpools').split('.')[0]}
      </h3>
      <p className="text-sm text-bambu-gray text-center max-w-sm mb-6">
        {hasFilters
          ? t('inventory.noSpoolsMatchDesc')
          : t('inventory.noSpools')
        }
      </p>
      {!hasFilters && (
        <Button onClick={onAddSpool}>
          <Package className="w-4 h-4" />
          {t('inventory.addSpool')}
        </Button>
      )}
    </div>
  );
}
