import React, { useState, useEffect, useMemo, useCallback } from 'react';
import { apiFetch } from '@/utils/api';
import { useSearchParams } from 'react-router-dom';
import { useQuery, keepPreviousData } from '@tanstack/react-query';
import { motion } from 'framer-motion';
import { Settings2, Search, X } from 'lucide-react';
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuTrigger,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuCheckboxItem
} from "@/components/ui/dropdown-menu";
import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/components/ui/pagination";
import { ProductMetric, ProductMetricColumnKey, ActiveFilterValue } from "@/types/products";
import { ProductTable } from "@/components/products/ProductTable";
import { ProductFilters } from "@/components/products/ProductFilters";
import { ProductDetail } from "@/components/products/ProductDetail";
import { ProductViews } from "@/components/products/ProductViews";
import { ProductTableSkeleton } from "@/components/products/ProductTableSkeleton";
import { ProductSummaryCards } from "@/components/products/ProductSummaryCards";
import { toast } from "sonner";
import { useDebounce } from "@/hooks/useDebounce";
import { AVAILABLE_COLUMNS, VIEW_COLUMNS, COLUMNS_BY_GROUP } from "@/components/products/columnDefinitions";
import { transformMetricsRow, OPERATOR_MAP } from "@/utils/transformUtils";

// --- ColumnToggle Component ---
// Extracted as a proper component for stable React identity and correct internal state management.

interface ColumnToggleProps {
  visibleColumns: Set<ProductMetricColumnKey>;
  onColumnVisibilityChange: (column: ProductMetricColumnKey, isVisible: boolean) => void;
  onResetToDefault: () => void;
}

function ColumnToggle({ visibleColumns, onColumnVisibilityChange, onResetToDefault }: ColumnToggleProps) {
  const [open, setOpen] = React.useState(false);

  return (
    <DropdownMenu open={open} onOpenChange={setOpen} modal={false}>
      <DropdownMenuTrigger asChild>
        <Button variant="outline" className="ml-auto">
          <Settings2 className="mr-2 h-4 w-4" />
          Columns
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent
        align="end"
        className="w-[600px] max-h-[calc(100vh-16rem)] overflow-y-auto"
        onCloseAutoFocus={(e) => e.preventDefault()}
        onPointerDownOutside={(e) => {
          if (!(e.target as HTMLElement).closest('[role="dialog"]')) {
            setOpen(false);
          }
        }}
        onInteractOutside={(e) => {
          if ((e.target as HTMLElement).closest('[role="dialog"]')) {
            e.preventDefault();
          }
        }}
      >
        <div className="sticky top-0 bg-background z-10 flex items-center justify-between">
          <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
          <Button
            variant="secondary"
            size="sm"
            onClick={(e) => {
              onResetToDefault();
              e.stopPropagation();
            }}
          >
            Reset to Default
          </Button>
        </div>
        <DropdownMenuSeparator className="sticky top-[29px] bg-background z-10" />
        <div style={{ columnCount: 3, columnGap: '2rem' }} className="p-2">
          {Object.entries(COLUMNS_BY_GROUP).map(([group, columns]) => (
            <div key={group} style={{ breakInside: 'avoid' }} className="mb-4">
              <DropdownMenuLabel className="text-xs font-semibold text-muted-foreground mb-2">
                {group}
              </DropdownMenuLabel>
              <div className="flex flex-col gap-1">
                {columns.map((column) => (
                  <DropdownMenuCheckboxItem
                    key={column.key}
                    className="capitalize"
                    checked={visibleColumns.has(column.key)}
                    onCheckedChange={(checked) => {
                      onColumnVisibilityChange(column.key, checked);
                    }}
                    onSelect={(e) => {
                      e.preventDefault();
                    }}
                  >
                    {column.label}
                  </DropdownMenuCheckboxItem>
                ))}
              </div>
            </div>
          ))}
        </div>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

// --- Helper: Transform frontend filter state to API query params ---

function transformFilters(filters: Record<string, any>): Record<string, any> {
  const transformedFilters: Record<string, any> = {};

  Object.entries(filters).forEach(([key, value]) => {
    if (typeof value === 'object' && value !== null && 'operator' in value) {
      const operatorSuffix = OPERATOR_MAP[value.operator] || 'eq';

      // For between, send as comma-separated string (backend splits on comma)
      if (value.operator === 'between' && Array.isArray(value.value)) {
        transformedFilters[`${key}_${operatorSuffix}`] = value.value.join(',');
      } else {
        transformedFilters[`${key}_${operatorSuffix}`] = value.value;
      }
    } else {
      // Simple values (from select/boolean filters) are passed as-is
      transformedFilters[key] = value;
    }
  });

  return transformedFilters;
}

// --- Main Products Page Component ---

export function Products() {
  const [searchParams, setSearchParams] = useSearchParams();
  const [filters, setFilters] = useState<Record<string, ActiveFilterValue>>({});
  const [searchQuery, setSearchQuery] = useState('');
  const debouncedSearch = useDebounce(searchQuery, 300);
  const [sortColumn, setSortColumn] = useState<ProductMetricColumnKey>('title');
  const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
  // Track last sort direction for each column
  const [columnSortDirections, setColumnSortDirections] = useState<Record<string, 'asc' | 'desc'>>({
    'title': 'asc' // Initialize with default sort column and direction
  });
  const [currentPage, setCurrentPage] = useState(1);
  const [activeView, setActiveView] = useState(searchParams.get('view') || "all");
  const [pageSize] = useState(50);
  const [showNonReplenishable, setShowNonReplenishable] = useState(false);
  const [showInvisible, setShowInvisible] = useState(false);
  const [selectedProductId, setSelectedProductId] = useState<number | null>(null);
  const searchInputRef = React.useRef<HTMLInputElement>(null);

  // Store visible columns and order for each view
  const [viewColumns, setViewColumns] = useState<Record<string, Set<ProductMetricColumnKey>>>(() => {
    const initialColumns: Record<string, Set<ProductMetricColumnKey>> = {};
    Object.entries(VIEW_COLUMNS).forEach(([view, columns]) => {
      initialColumns[view] = new Set(columns);
    });
    return initialColumns;
  });

  const [viewColumnOrder, setViewColumnOrder] = useState<Record<string, ProductMetricColumnKey[]>>(() => {
    const initialOrder: Record<string, ProductMetricColumnKey[]> = {};
    Object.entries(VIEW_COLUMNS).forEach(([view, defaultColumns]) => {
      initialOrder[view] = [
        ...defaultColumns,
        ...AVAILABLE_COLUMNS.map(col => col.key).filter(key => !defaultColumns.includes(key))
      ];
    });
    return initialOrder;
  });

  // Get current view's columns, auto-adding indicator columns when toggles are active
  const visibleColumns = useMemo(() => {
    const columns = new Set(viewColumns[activeView] || VIEW_COLUMNS.all);

    // Add isReplenishable column when showing non-replenishable products for better visibility
    if (showNonReplenishable) {
      columns.add('isReplenishable');
    }
    // Add isVisible column when showing invisible products so users can distinguish them
    if (showInvisible) {
      columns.add('isVisible');
    }

    return columns;
  }, [viewColumns, activeView, showNonReplenishable, showInvisible]);

  const columnOrder = viewColumnOrder[activeView] || viewColumnOrder.all;

  // Handle column visibility changes
  const handleColumnVisibilityChange = useCallback((column: ProductMetricColumnKey, isVisible: boolean) => {
    setViewColumns(prev => ({
      ...prev,
      [activeView]: isVisible
        ? new Set([...prev[activeView], column])
        : new Set([...prev[activeView]].filter(col => col !== column))
    }));
  }, [activeView]);

  // Handle column order changes (newVisibleOrder only contains visible columns from drag reorder)
  const handleColumnOrderChange = (newVisibleOrder: ProductMetricColumnKey[]) => {
    setViewColumnOrder(prev => {
      const oldFullOrder = prev[activeView] || [];
      // Append hidden columns (preserving their relative order) after the reordered visible columns
      const hiddenColumns = oldFullOrder.filter(col => !visibleColumns.has(col));
      return {
        ...prev,
        [activeView]: [...newVisibleOrder, ...hiddenColumns]
      };
    });
  };

  // Reset columns to default for current view
  const resetColumnsToDefault = useCallback(() => {
    setViewColumns(prev => ({
      ...prev,
      [activeView]: new Set(VIEW_COLUMNS[activeView] || VIEW_COLUMNS.all)
    }));
    setViewColumnOrder(prev => ({
      ...prev,
      [activeView]: [
        ...(VIEW_COLUMNS[activeView] || VIEW_COLUMNS.all),
        ...AVAILABLE_COLUMNS.map(col => col.key)
          .filter(key => !(VIEW_COLUMNS[activeView] || VIEW_COLUMNS.all).includes(key))
      ]
    }));
  }, [activeView]);

  // Merge search query into filters for the API call
  const effectiveFilters = useMemo(() => {
    const merged = { ...filters };
    if (debouncedSearch.trim()) {
      merged['title'] = { value: debouncedSearch.trim(), operator: 'contains' as const };
    }
    return merged;
  }, [filters, debouncedSearch]);

  // Fetch products data with stable callback reference
  const fetchProducts = useCallback(async () => {
    try {
      const params = new URLSearchParams();
      params.append('page', currentPage.toString());
      params.append('limit', pageSize.toString());

      if (sortColumn) {
        params.append('sort', sortColumn);
        params.append('order', sortDirection);
      }

      if (activeView && activeView !== 'all') {
        const stockStatus = activeView === 'at-risk' ? 'At Risk' :
                           activeView === 'reorder' ? 'Reorder Soon' :
                           activeView === 'overstocked' ? 'Overstock' :
                           activeView === 'new' ? 'New' :
                           activeView.charAt(0).toUpperCase() + activeView.slice(1);
        params.append('stock_status', stockStatus);
      }

      // Transform filters to match API expectations
      const transformedFilters = transformFilters(effectiveFilters);
      Object.entries(transformedFilters).forEach(([key, value]) => {
        if (value !== undefined && value !== null && value !== '') {
          if (Array.isArray(value)) {
            params.append(key, value.join(','));
          } else {
            params.append(key, value.toString());
          }
        }
      });

      if (showNonReplenishable) {
        params.append('showNonReplenishable', 'true');
      }

      if (showInvisible) {
        params.append('showInvisible', 'true');
      }

      const response = await apiFetch(`/api/metrics?${params.toString()}`, {credentials: 'include'});
      if (!response.ok) throw new Error('Failed to fetch products');

      const data = await response.json();

      // Use shared transform utility instead of inline conversion
      const transformedProducts = data.metrics?.map((product: any) => transformMetricsRow(product)) || [];

      return {
        products: transformedProducts,
        pagination: data.pagination || {
          total: 0,
          pages: 0,
          currentPage: 1,
          limit: pageSize
        },
        filters: data.appliedQuery?.filters || {}
      };
    } catch (error) {
      console.error('Error fetching products:', error);
      toast.error("Failed to fetch products. Please try again.");
      return null;
    }
  }, [currentPage, pageSize, sortColumn, sortDirection, activeView, effectiveFilters, showNonReplenishable, showInvisible]);

  // Query for filter options
  const { data: filterOptionsData, isLoading: isLoadingFilterOptions } = useQuery({
    queryKey: ['filterOptions'],
    queryFn: async () => {
      try {
        const response = await apiFetch('/api/metrics/filter-options');
        if (!response.ok) throw new Error('Failed to fetch filter options');
        const data = await response.json();

        // Ensure we have the expected structure with correct casing
        return {
          vendors: data.vendors || [],
          brands: data.brands || [],
          abcClasses: data.abc_classes || data.abcClasses || []
        };
      } catch (error) {
        console.error('Error fetching filter options:', error);
        return { vendors: [], brands: [], abcClasses: [] };
      }
    },
    staleTime: 5 * 60 * 1000, // Cache for 5 minutes
  });

  // Query for summary data (powers KPI cards and view counts)
  const { data: summaryData } = useQuery({
    queryKey: ['productsSummary', showNonReplenishable, showInvisible],
    queryFn: async () => {
      const params = new URLSearchParams();
      if (showNonReplenishable) params.append('showNonReplenishable', 'true');
      if (showInvisible) params.append('showInvisible', 'true');
      const response = await apiFetch(`/api/metrics/summary?${params.toString()}`, { credentials: 'include' });
      if (!response.ok) throw new Error('Failed to fetch summary');
      return response.json();
    },
    staleTime: 60 * 1000,
  });

  // Query for products data
  const { data, isFetching } = useQuery({
    queryKey: ['products', currentPage, pageSize, sortColumn, sortDirection, activeView, effectiveFilters, showNonReplenishable, showInvisible],
    queryFn: fetchProducts,
    placeholderData: keepPreviousData,
  });

  // Reset page when debounced search changes
  useEffect(() => {
    setCurrentPage(1);
  }, [debouncedSearch]);

  // Update current page if it exceeds the total pages
  useEffect(() => {
    if (data?.pagination.pages && currentPage > data.pagination.pages) {
      setCurrentPage(1);
    }
  }, [currentPage, data?.pagination.pages]);

  // Global keyboard shortcut: "/" to focus search
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === '/' && !['INPUT', 'TEXTAREA', 'SELECT'].includes((e.target as HTMLElement).tagName)) {
        e.preventDefault();
        searchInputRef.current?.focus();
      }
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, []);

  // Handle sort column change with improved column-specific direction memory
  const handleSort = (column: ProductMetricColumnKey) => {
    let nextDirection: 'asc' | 'desc';

    if (sortColumn === column) {
      // If clicking the same column, toggle direction
      nextDirection = sortDirection === 'asc' ? 'desc' : 'asc';
    } else {
      // If clicking a different column:
      // 1. If this column has been sorted before, use the stored direction
      // 2. Otherwise use a sensible default (asc for text, desc for numeric columns)
      const prevDirection = columnSortDirections[column];

      if (prevDirection) {
        // Use the stored direction
        nextDirection = prevDirection;
      } else {
        // Determine sensible default based on column type
        const columnDef = AVAILABLE_COLUMNS.find(c => c.key === column);
        const isNumeric = columnDef?.group === 'Sales' ||
                        columnDef?.group === 'Financial' ||
                        columnDef?.group === 'Stock' ||
                        ['currentPrice', 'currentRegularPrice', 'currentCostPrice', 'currentStock'].includes(column);

        // Start with descending for numeric columns (to see highest values first)
        // Start with ascending for text columns (alphabetical order)
        nextDirection = isNumeric ? 'desc' : 'asc';
      }
    }

    // Update the current sort state
    setSortDirection(nextDirection);
    setSortColumn(column);

    // Remember this column's sort direction for next time
    setColumnSortDirections(prev => ({
      ...prev,
      [column]: nextDirection
    }));
  };

  // Handle filter changes
  const handleFilterChange = (newFilters: Record<string, ActiveFilterValue>) => {
    setFilters(newFilters);
    setCurrentPage(1);
  };

  const handleClearFilters = () => {
    setFilters({});
    setSearchQuery('');
    setCurrentPage(1);
  };

  // Function to handle page changes
  const handlePageChange = (page: number) => {
    setCurrentPage(page);
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };

  // Calculate pagination numbers
  const totalPages = data?.pagination.pages || 1;
  const showEllipsis = totalPages > 7;
  const pageNumbers = showEllipsis
    ? currentPage <= 4
      ? [1, 2, 3, 4, 5]
      : currentPage >= totalPages - 3
        ? [totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages]
        : [currentPage - 2, currentPage - 1, currentPage, currentPage + 1, currentPage + 2]
    : Array.from({ length: totalPages }, (_, i) => i + 1);

  // Update URL when view changes, reset filters and conditionally reset sort
  const handleViewChange = (view: string) => {
    setActiveView(view);
    setCurrentPage(1);
    setFilters({}); // Clear filters when switching views to avoid confusion
    setSearchQuery(''); // Clear search when switching views

    // Reset sort if the current sort column isn't visible in the new view
    const newViewColumns = VIEW_COLUMNS[view] || VIEW_COLUMNS.all;
    if (!newViewColumns.includes(sortColumn)) {
      setSortColumn('title');
      setSortDirection('asc');
    }

    setSearchParams(prev => {
      const newParams = new URLSearchParams(prev);
      newParams.set('view', view);
      return newParams;
    });
  };

  // Sync with URL params when they change
  useEffect(() => {
    const viewParam = searchParams.get('view');
    if (viewParam && viewParam !== activeView) {
      setActiveView(viewParam);
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchParams]);

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      transition={{ duration: 0.2 }}
      className="container mx-auto py-6 space-y-4"
    >
      <div className="flex items-center justify-between">
        <h1 className="text-3xl font-bold tracking-tight">Products</h1>
        <div className="relative w-80">
          <Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
          <Input
            ref={searchInputRef}
            type="text"
            placeholder='Search products by name... (press "/")'
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            className="pl-9 pr-8 h-9"
          />
          {searchQuery && (
            <button
              onClick={() => setSearchQuery('')}
              className="absolute right-2 top-2.5 text-muted-foreground hover:text-foreground"
            >
              <X className="h-4 w-4" />
            </button>
          )}
        </div>
      </div>

      <ProductSummaryCards
        activeView={activeView}
        showNonReplenishable={showNonReplenishable}
        showInvisible={showInvisible}
      />

      <ProductViews
        activeView={activeView}
        onViewChange={handleViewChange}
        viewCounts={summaryData ?? null}
      />

      <div>
        <div className="flex items-center justify-between mb-4">
          <ProductFilters
            filterOptions={{
              vendors: filterOptionsData?.vendors ?? [],
              brands: filterOptionsData?.brands ?? [],
              abcClasses: filterOptionsData?.abcClasses ?? []
            }}
            isLoadingOptions={isLoadingFilterOptions}
            onFilterChange={handleFilterChange}
            onClearFilters={handleClearFilters}
            activeFilters={filters}
          />
          <div className="flex items-center gap-4">
            <div className="flex items-center space-x-2">
              <Switch
                id="show-non-replenishable"
                checked={showNonReplenishable}
                onCheckedChange={(checked) => {
                  setShowNonReplenishable(checked);
                  setCurrentPage(1);
                }}
              />
              <Label htmlFor="show-non-replenishable">Show Non-Replenishable</Label>
            </div>
            <div className="flex items-center space-x-2">
              <Switch
                id="show-invisible"
                checked={showInvisible}
                onCheckedChange={(checked) => {
                  setShowInvisible(checked);
                  setCurrentPage(1);
                }}
              />
              <Label htmlFor="show-invisible">Show Invisible</Label>
            </div>
            {data?.pagination?.total !== undefined && (
              <div className="text-sm text-muted-foreground">
                {data.pagination.total.toLocaleString()} products
              </div>
            )}
            <ColumnToggle
              visibleColumns={visibleColumns}
              onColumnVisibilityChange={handleColumnVisibilityChange}
              onResetToDefault={resetColumnsToDefault}
            />
          </div>
        </div>

        {isFetching ? (
          <ProductTableSkeleton />
        ) : (
          <div className="space-y-4">
            <ProductTable
              products={data?.products?.map((product: ProductMetric) => ({
                ...product,
                status: product.status || 'Unknown'
              })) || []}
              onSort={handleSort}
              sortColumn={sortColumn}
              sortDirection={sortDirection}
              visibleColumns={visibleColumns}
              columnDefs={AVAILABLE_COLUMNS}
              columnOrder={columnOrder}
              onColumnOrderChange={handleColumnOrderChange}
              onViewProduct={(productId) => setSelectedProductId(productId)}
            />

            {totalPages > 1 && (
              <Pagination>
                <PaginationContent>
                  <PaginationItem>
                    <PaginationPrevious
                      href="#"
                      onClick={(e) => {
                        e.preventDefault();
                        handlePageChange(Math.max(1, currentPage - 1));
                      }}
                      aria-disabled={currentPage === 1}
                    />
                  </PaginationItem>

                  {showEllipsis && currentPage > 4 && (
                    <>
                      <PaginationItem>
                        <PaginationLink
                          href="#"
                          onClick={(e) => {
                            e.preventDefault();
                            handlePageChange(1);
                          }}
                        >
                          1
                        </PaginationLink>
                      </PaginationItem>
                      <PaginationItem>
                        <PaginationEllipsis />
                      </PaginationItem>
                    </>
                  )}

                  {pageNumbers.map((page) => (
                    <PaginationItem key={page}>
                      <PaginationLink
                        href="#"
                        isActive={currentPage === page}
                        onClick={(e) => {
                          e.preventDefault();
                          handlePageChange(page);
                        }}
                      >
                        {page}
                      </PaginationLink>
                    </PaginationItem>
                  ))}

                  {showEllipsis && currentPage < totalPages - 3 && (
                    <>
                      <PaginationItem>
                        <PaginationEllipsis />
                      </PaginationItem>
                      <PaginationItem>
                        <PaginationLink
                          href="#"
                          onClick={(e) => {
                            e.preventDefault();
                            handlePageChange(totalPages);
                          }}
                        >
                          {totalPages}
                        </PaginationLink>
                      </PaginationItem>
                    </>
                  )}

                  <PaginationItem>
                    <PaginationNext
                      href="#"
                      onClick={(e) => {
                        e.preventDefault();
                        handlePageChange(Math.min(totalPages, currentPage + 1));
                      }}
                      aria-disabled={currentPage === totalPages}
                    />
                  </PaginationItem>
                </PaginationContent>
              </Pagination>
            )}
          </div>
        )}
      </div>

      <ProductDetail
        productId={selectedProductId}
        onClose={() => setSelectedProductId(null)}
      />
    </motion.div>
  );
}
