import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  FlatList,
  Modal,
  ScrollView,
  SafeAreaView,
  NativeSyntheticEvent,
  NativeScrollEvent,
  ViewStyle,
  TextStyle,
  TouchableWithoutFeedback,
} from 'react-native';

import { styles } from './styles';

// Define types for data items and filters
interface DataItem {
  id: string | number;
  [key: string]: string | number | boolean | null | undefined;
}

interface RangeFilter {
  min: number | null;
  max: number | null;
}

type FilterValue = string | null | RangeFilter;

interface FilterMap {
  [key: string]: FilterValue;
}

interface SortConfig {
  field: string | null;
  order: 'asc' | 'desc' | null;
}

interface DynamicTableProps {
  initialData: DataItem[];
  isFilter?: boolean;
  sortByColumn?: boolean;
  isSearch?: boolean;
  cellStyle?: ViewStyle;
  headerStyle?: ViewStyle;
  ignoredHeaders?: string[];
  filterButtonStyle?: ViewStyle;
  filterButtonTextStyle?: TextStyle;
  filterContainerStyle?: ViewStyle;
  filterContainerApplyButtonStyle?: ViewStyle;
  filterContainerApplyButtonTextStyle?: TextStyle;
  filterContainerResetButtonStyle?: ViewStyle;
  filterContainerResetButtonTextStyle?: TextStyle;
  contentPaddingBottom?: number;
  emptyMessage?: string;
  filterTitle?: string;
  activeTabButtonColor?: string;
  showApplyButton?: boolean;
  filterContainerFieldOptionStyle?: ViewStyle;
  filterContainerFieldOptionTextStyle?: TextStyle;
  filterContainerFieldOptionActiveTextStyle?: string;
  filterContainerValueOptionStyle?: ViewStyle;
  filterContainerValueOptionTextStyle?: TextStyle;
  filterContainerValueOptionActiveTextStyle?: string;
}

const DynamicTable: React.FC<DynamicTableProps> = ({
  initialData = [],
  isFilter = true,
  sortByColumn = true,
  isSearch = true,
  cellStyle = {},
  headerStyle = {},
  ignoredHeaders = [],
  filterButtonStyle,
  filterButtonTextStyle,
  filterContainerStyle,
  filterContainerApplyButtonStyle,
  filterContainerApplyButtonTextStyle,
  filterContainerResetButtonStyle,
  filterContainerResetButtonTextStyle,
  contentPaddingBottom,
  emptyMessage,
  filterTitle,
  activeTabButtonColor,
  showApplyButton = true,
  filterContainerFieldOptionStyle,
  filterContainerFieldOptionTextStyle,
  filterContainerFieldOptionActiveTextStyle,
  filterContainerValueOptionStyle,
  filterContainerValueOptionTextStyle,
  filterContainerValueOptionActiveTextStyle,
}) => {
  // Dynamic columns detection
  const columns = useMemo(() => {
    if (initialData.length === 0) {
      return [];
    }
    const sample = initialData[0];
    return Object.keys(sample).filter(key => !ignoredHeaders?.includes(key));
  }, [initialData, ignoredHeaders]);

  // Get unique values for each column (for filters)
  const uniqueValuesMap = useMemo(() => {
    const map: { [key: string]: string[] } = {};
    columns.forEach(column => {
      const values = [
        ...new Set(initialData.map(item => String(item[column]))),
      ];
      map[column] = values;
    });
    return map;
  }, [columns, initialData]);

  // Calculate column widths based on content
  const columnWidths = useMemo(() => {
    const widths: { [key: string]: number } = {};
    columns.forEach(column => {
      // Start with the column name length (plus some padding)
      let maxWidth = column.length * 10 + 20;

      // Find the longest content in this column
      initialData.forEach(item => {
        const contentLength = String(item[column]).length;
        maxWidth = Math.max(maxWidth, contentLength * 8 + 20);
      });

      // Set minimum and maximum widths
      widths[column] = Math.max(100, Math.min(maxWidth, 200));
    });
    return widths;
  }, [columns, initialData]);

  // Calculate total table width
  const tableWidth = useMemo(() => {
    return Object.values(columnWidths).reduce((sum, width) => sum + width, 0);
  }, [columnWidths]);

  const [data, setData] = useState<DataItem[]>(initialData);
  const [searchQuery, setSearchQuery] = useState<string>('');
  const [sortConfig, setSortConfig] = useState<SortConfig>({
    field: null,
    order: null,
  });
  const [showFilterModal, setShowFilterModal] = useState<boolean>(false);
  const [activeFilterColumn, setActiveFilterColumn] = useState<string | null>(
    null,
  );
  const [filters, setFilters] = useState<FilterMap>({});

  // Refs for synchronized scrolling
  const headerScrollViewRef = useRef<ScrollView>(null);
  const contentScrollViewRef = useRef<ScrollView>(null);

  const handleContentScroll = useCallback(
    (event: NativeSyntheticEvent<NativeScrollEvent>) => {
      const offsetX = event.nativeEvent.contentOffset.x;
      if (headerScrollViewRef.current) {
        headerScrollViewRef.current.scrollTo({ x: offsetX, animated: false });
      }
    },
    [],
  );

  // Apply all current filters to the data
  const applyAllFilters = useCallback(
    (sourceData: DataItem[]): void => {
      let result = [...sourceData];

      Object.entries(filters).forEach(([column, value]) => {
        if (value !== null && value !== undefined) {
          if (
            typeof value === 'object' &&
            (value.min !== null || value.max !== null)
          ) {
            // Range filter (for numeric values)
            if (value.min !== null) {
              result = result.filter(
                item => value.min !== null && Number(item[column]) >= value.min,
              );
            }
            if (value.max !== null) {
              result = result.filter(
                item => value.max !== null && Number(item[column]) <= value.max,
              );
            }
          } else if (value !== '') {
            // Single value filter
            result = result.filter(
              item => String(item[column]) === String(value),
            );
          }
        }
      });

      // Apply current sort if any
      if (sortConfig.field) {
        result = sortData(result, sortConfig.field, sortConfig.order!);
      }

      setData(result);
    },
    [filters, sortConfig.field, sortConfig.order],
  );

  // Search function that works across all fields
  useEffect(() => {
    if (searchQuery.trim() === '') {
      applyAllFilters(initialData);
    } else {
      const filteredData = initialData.filter(item =>
        columns.some(column =>
          String(item[column])
            .toLowerCase()
            .includes(searchQuery.toLowerCase()),
        ),
      );
      applyAllFilters(filteredData);
    }
  }, [searchQuery, initialData, columns, applyAllFilters]);

  // Handle sorting
  const handleSort = (field: string): void => {
    let order: 'asc' | 'desc' = 'asc';

    if (sortConfig.field === field && sortConfig.order === 'asc') {
      order = 'desc';
    }

    setSortConfig({ field, order });

    const sortedData = sortData([...data], field, order);
    setData(sortedData);
  };

  // Sort function that handles different data types
  const sortData = (
    dataToSort: DataItem[],
    field: string,
    order: 'asc' | 'desc',
  ): DataItem[] => {
    return [...dataToSort].sort((a, b) => {
      const aValue = a[field];
      const bValue = b[field];

      // Handle numeric values
      if (!isNaN(Number(aValue)) && !isNaN(Number(bValue))) {
        return order === 'asc'
          ? Number(aValue) - Number(bValue)
          : Number(bValue) - Number(aValue);
      }

      // Handle string values
      const aString = String(aValue).toLowerCase();
      const bString = String(bValue).toLowerCase();

      if (order === 'asc') {
        return aString > bString ? 1 : -1;
      } else {
        return aString < bString ? 1 : -1;
      }
    });
  };

  // Handle filter selection
  const handleFilterSelect = useCallback(
    (column: string, value: string): void => {
      const isNumeric = !isNaN(Number(initialData[0][column]));

      if (isNumeric) {
        // For numeric columns, open range filter
        setFilters(prev => ({
          ...prev,
          [column]: {
            min:
              prev[column] && typeof prev[column] === 'object'
                ? (prev[column] as RangeFilter).min
                : null,
            max:
              prev[column] && typeof prev[column] === 'object'
                ? (prev[column] as RangeFilter).max
                : null,
          },
        }));
      } else {
        // For categorical columns, toggle selection
        setFilters(prev => ({
          ...prev,
          [column]: prev[column] === value ? null : value,
        }));
      }
    },
    [initialData],
  );

  // Update numeric filter range
  const updateRangeFilter = useCallback(
    (column: string, type: 'min' | 'max', value: string): void => {
      setFilters(prev => ({
        ...prev,
        [column]: {
          ...((prev[column] as RangeFilter) || { min: null, max: null }),
          [type]: value === '' ? null : Number(value),
        },
      }));
    },
    [],
  );

  // Apply filters and close modal
  const applyFilters = useCallback(() => {
    applyAllFilters(initialData);
    setShowFilterModal(false);
  }, [applyAllFilters, initialData]);

  // Reset all filters
  const resetFilters = useCallback(() => {
    setFilters({});
    setData(initialData);
    setShowFilterModal(false);
  }, [initialData]);

  // Determine if a column is numeric
  const isNumericColumn = useCallback(
    (column: string): boolean => {
      return initialData.length > 0 && !isNaN(Number(initialData[0][column]));
    },
    [initialData],
  );

  // Dynamic table header component
  const TableHeader = useCallback(
    () => (
      <View style={[styles.headerRow, { width: tableWidth }]}>
        {columns.map((column, index) => (
          <TouchableOpacity
            disabled={!sortByColumn}
            key={column}
            activeOpacity={0.8}
            style={[
              headerStyle,
              styles.headerCell,
              {
                width: columnWidths[column],
                borderTopWidth: 1,
                borderBottomWidth: 1,
                borderColor: '#e0e0e0',
              },
              index === 0 && { borderLeftWidth: 1 },
              index === columns.length - 1 && { borderRightWidth: 1 },
            ]}
            onPress={() => handleSort(column)}>
            <Text
              style={styles.headerText}
              numberOfLines={1}
              ellipsizeMode="tail">
              {column.charAt(0).toUpperCase() + column.slice(1)}
            </Text>
            {sortConfig.field === column && (
              <Text>{sortConfig.order === 'asc' ? '▲' : '▼'}</Text>
            )}
          </TouchableOpacity>
        ))}
      </View>
    ),
    [
      columns,
      sortConfig,
      columnWidths,
      tableWidth,
      sortByColumn,
      headerStyle,
      handleSort,
    ],
  );

  // Dynamic row renderer
  const renderItem = useCallback(
    ({ item }: { item: DataItem }) => (
      <View style={[styles.row, { width: tableWidth }, cellStyle]}>
        {columns.map(column => (
          <TouchableOpacity
            onPress={() => {
              console.log({ column, item });
            }}
            key={`${item.id}-${column}`}>
            <Text
              style={[styles.cell, { width: columnWidths[column] }]}
              numberOfLines={2}
              ellipsizeMode="tail">
              {item[column]}
            </Text>
          </TouchableOpacity>
        ))}
      </View>
    ),
    [columns, columnWidths, tableWidth, cellStyle],
  );

  // Key extractor for FlatList
  const keyExtractor = useCallback((item: DataItem) => item.id.toString(), []);

  return (
    <SafeAreaView style={styles.container}>
      {/* Search and filter header */}
      <View style={styles.header}>
        {isSearch ? (
          <View style={styles.searchContainer}>
            <Text style={styles.searchIcon}>🔍</Text>
            <TextInput
              style={styles.searchInput}
              placeholder="Search"
              value={searchQuery}
              onChangeText={setSearchQuery}
            />
          </View>
        ) : null}
        {isFilter ? (
          <TouchableOpacity
            style={[
              filterButtonStyle ? filterButtonStyle : styles.filterButton,
            ]}
            onPress={() => {
              setActiveFilterColumn(columns[0]);
              setShowFilterModal(true);
            }}>
            <Text
              style={
                filterButtonTextStyle
                  ? filterButtonTextStyle
                  : styles.filterButtonText
              }>
              Filter
            </Text>
          </TouchableOpacity>
        ) : null}
      </View>

      {/* Data table with horizontal scroll */}
      <View style={[styles.tableContainer, { padding: 20 }]}>
        {/* Fixed header that syncs with content scroll */}
        <ScrollView
          ref={headerScrollViewRef}
          horizontal
          scrollEnabled={false}
          showsHorizontalScrollIndicator={false}>
          <TableHeader />
        </ScrollView>

        {/* Scrollable table content */}
        <ScrollView
          ref={contentScrollViewRef}
          horizontal
          onScroll={handleContentScroll}
          scrollEventThrottle={16}
          bounces={false}
          showsHorizontalScrollIndicator={false}>
          <FlatList
            bounces={false}
            data={data}
            renderItem={renderItem}
            keyExtractor={keyExtractor}
            initialNumToRender={10}
            maxToRenderPerBatch={10}
            windowSize={10}
            removeClippedSubviews={true}
            ListEmptyComponent={
              <View style={styles.emptyState}>
                <Text style={styles.emptyStateText}>
                  {emptyMessage ? emptyMessage : 'No results found'}
                </Text>
              </View>
            }
            contentContainerStyle={{ paddingBottom: contentPaddingBottom ?? 120 }} // Increased to fix hidden rows
            showsVerticalScrollIndicator={true}
          />
        </ScrollView>
      </View>

      {/* Filter modal */}
      <Modal visible={showFilterModal} transparent={true} animationType="slide">
        <TouchableWithoutFeedback
          onPress={() => {
            setShowFilterModal(false);
          }}>
          <View style={styles.modalOverlay}>
            <View style={[styles.modalContent, filterContainerStyle]}>
              <View style={styles.modalHeader}>
                <Text style={styles.modalTitle}>{filterTitle ?? 'Filter'}</Text>
                <ScrollView
                  horizontal
                  showsHorizontalScrollIndicator={false}
                  style={styles.tabsContainer}>
                  {columns.map(column => (
                    <TouchableOpacity
                      key={column}
                      style={[
                        filterContainerFieldOptionStyle || styles.tabButton,
                        activeFilterColumn === column && {
                          backgroundColor: activeTabButtonColor || '#5C6B73',
                        },
                      ]}
                      onPress={() => setActiveFilterColumn(column)}>
                      <Text
                        style={[
                          filterContainerFieldOptionTextStyle ?? null,
                          activeFilterColumn === column
                            ? {
                              color:
                                filterContainerFieldOptionActiveTextStyle ||
                                '#fff',
                            }
                            : {},
                        ]}>
                        {column.charAt(0).toUpperCase() + column.slice(1)}
                      </Text>
                    </TouchableOpacity>
                  ))}
                </ScrollView>
              </View>
              {activeFilterColumn && (
                <View style={styles.filterContent}>
                  {isNumericColumn(activeFilterColumn) ? (
                    // Numeric filter with range inputs
                    <View style={styles.rangeFilterContainer}>
                      <Text style={styles.filterLabel}>Range</Text>
                      <View style={styles.rangeInputs}>
                        <TextInput
                          style={styles.rangeInput}
                          placeholder="Min"
                          keyboardType="numeric"
                          value={
                            typeof filters[activeFilterColumn] === 'object' &&
                              filters[activeFilterColumn]?.min !== null &&
                              filters[activeFilterColumn]?.min !== undefined
                              ? String(filters[activeFilterColumn]?.min)
                              : ''
                          }
                          onChangeText={text =>
                            updateRangeFilter(activeFilterColumn, 'min', text)
                          }
                        />
                        <Text> - </Text>
                        <TextInput
                          style={styles.rangeInput}
                          placeholder="Max"
                          keyboardType="numeric"
                          value={
                            typeof filters[activeFilterColumn] === 'object' &&
                              filters[activeFilterColumn]?.max !== null &&
                              filters[activeFilterColumn]?.max !== undefined
                              ? String(filters[activeFilterColumn]?.max)
                              : ''
                          }
                          onChangeText={text =>
                            updateRangeFilter(activeFilterColumn, 'max', text)
                          }
                        />
                      </View>
                    </View>
                  ) : (
                    // Categorical filter with options
                    <View style={styles.optionsFilterContainer}>
                      <Text style={styles.filterLabel}>
                        Select {activeFilterColumn}
                      </Text>
                      <View style={styles.optionsList}>
                        {uniqueValuesMap[activeFilterColumn].map(value => (
                          <TouchableOpacity
                            key={value}
                            style={[
                              filterContainerValueOptionStyle ||
                              styles.optionButton,
                              filters[activeFilterColumn] === value &&
                              styles.selectedOption,
                            ]}
                            onPress={() =>
                              handleFilterSelect(activeFilterColumn, value)
                            }>
                            <Text
                              style={[
                                filters[activeFilterColumn] === value && {
                                  color:
                                    filterContainerValueOptionActiveTextStyle ||
                                    '#fff',
                                },
                                filterContainerValueOptionTextStyle ||
                                styles.optionText,
                              ]}
                              numberOfLines={1}
                              ellipsizeMode="tail">
                              {value}
                            </Text>
                          </TouchableOpacity>
                        ))}
                      </View>
                    </View>
                  )}
                </View>
              )}
              <View style={styles.modalButtons}>
                <TouchableOpacity
                  style={filterContainerResetButtonStyle || styles.modalButton}
                  onPress={resetFilters}>
                  <Text style={filterContainerResetButtonTextStyle || null}>Reset</Text>
                </TouchableOpacity>
                {showApplyButton ? (
                  <TouchableOpacity
                    style={[filterContainerApplyButtonStyle || styles.modalButton]}
                    onPress={applyFilters}>
                    <Text
                      style={filterContainerApplyButtonTextStyle || null}>
                      Apply
                    </Text>
                  </TouchableOpacity>
                ) : null}
              </View>
            </View>
          </View>
        </TouchableWithoutFeedback>
      </Modal>
    </SafeAreaView>
  );
};

export default DynamicTable;
