import React, { useEffect, useRef } from 'react';
import { Button, Checkbox, ScrollView, Separator, Text, XStack, YStack } from 'tamagui';
import { getIcon } from '../IconMapper.jsx';
import { PageNavBar } from '../PageNavBar.jsx';
import { useGridView } from './context.js';
import { getTypographyRoleProps } from '../../styles/index.js';
import {
  formatValueByColumn,
  getColumnJustify,
  getColumnLayoutStyle,
  resolveCellAlignment,
  resolveCellValue
} from './utils.js';

function DefaultGridCellRenderer({ value, column }) {
  return (
    <Text width="100%" textAlign={column.align || 'left'} color="$textPrimary" opacity={value == null || value === '' ? 0.6 : 1}>
      {formatValueByColumn(value, column)}
    </Text>
  );
}

function UtilityCell({ rowId }) {
  const grid = useGridView();
  const ChevronRightIcon = getIcon('chevron-right');

  if (!grid.selectable && !grid.nested) {
    return null;
  }

  if (grid.nested) {
    return (
      <XStack width={36} alignItems="center" justifyContent="center">
        {ChevronRightIcon ? <ChevronRightIcon size="sm" color="$textSecondary" /> : <Text color="$textSecondary">{'>'}</Text>}
      </XStack>
    );
  }

  return (
    <XStack width={36} alignItems="center" justifyContent="center">
      <Checkbox
        checked={grid.selectedIds.has(rowId)}
        onCheckedChange={() => grid.toggleSelectRow(rowId)}
        borderColor="$lineStrong"
        backgroundColor="$bgPanel"
        focusStyle={{ borderColor: '$accent' }}
      >
        <Checkbox.Indicator>
          {(() => {
            const Check = getIcon('check');
            return Check ? <Check size="sm" color="$accent" /> : null;
          })()}
        </Checkbox.Indicator>
      </Checkbox>
    </XStack>
  );
}

function useViewportTracking(enabled = true) {
  const grid = useGridView();
  const bodyRef = useRef(null);

  useEffect(() => {
    if (!enabled || typeof window === 'undefined') {
      return undefined;
    }

    const updateViewportWidth = () => {
      const element = bodyRef.current;
      if (!element) {
        return;
      }
      const nextWidth = Math.max(0, Math.round(element.getBoundingClientRect().width));
      grid.setTableViewportWidth((current) => (current === nextWidth ? current : nextWidth));
    };

    updateViewportWidth();
    window.addEventListener('resize', updateViewportWidth);

    return () => {
      window.removeEventListener('resize', updateViewportWidth);
    };
  }, [enabled, grid]);

  return bodyRef;
}

export function TableHeader({ visible = true, showTopBorder = true }) {
  const grid = useGridView();

  if (visible === false) {
    return null;
  }

  const activeColumns = grid.visibleColumns?.length ? grid.visibleColumns : grid.resolvedColumns;
  const CaretUp = getIcon('caret-up');
  const CaretDown = getIcon('caret-down');
  const allIds = (grid.rows || []).map((row) => row?.id).filter((id) => id != null);
  const selectedCount = allIds.filter((id) => grid.selectedIds.has(id)).length;
  const allSelected = allIds.length > 0 && selectedCount === allIds.length;
  const someSelected = selectedCount > 0 && !allSelected;
  const getNextSortDirection = (column) => {
    const activeSort = grid.sortBy.find((entry) => entry.field === column.field);
    if (!activeSort) {
      return 'ascending';
    }
    if (activeSort.direction === 'asc') {
      return 'descending';
    }
    return 'none';
  };

  return (
    <XStack
      alignItems="stretch"
      borderTopWidth={showTopBorder ? 1 : 0}
      borderBottomWidth={1}
      borderColor="$lineSubtle"
      backgroundColor="$bgPanel"
      paddingHorizontal="$2"
      paddingTop="$1"
      paddingBottom="$1"
      gap="$1"
    >
      {grid.selectable || grid.nested ? (
        <XStack width={36} alignItems="center" justifyContent="center">
          {grid.selectable ? (
            <Checkbox
              checked={allSelected ? true : someSelected ? 'indeterminate' : false}
              onCheckedChange={() => grid.toggleSelectAll?.()}
              borderColor="$lineStrong"
              backgroundColor="$bgPanel"
              focusStyle={{ borderColor: '$accent' }}
            >
              <Checkbox.Indicator>
                {(() => {
                  const Check = getIcon('check');
                  return Check ? <Check size="sm" color="$accent" /> : null;
                })()}
              </Checkbox.Indicator>
            </Checkbox>
          ) : null}
        </XStack>
      ) : null}
      {activeColumns.map((column) => {
        const activeSort = grid.sortBy.find((entry) => entry.field === column.field);
        const isActive = Boolean(activeSort);
        const direction = activeSort?.direction;
        const sortButtonLabel = `Sort ${column.label} ${getNextSortDirection(column)}`;
        const ChevronIcon = isActive
          ? (direction === 'asc' ? CaretUp : CaretDown)
          : CaretDown;
        const iconColor = isActive ? '$textSecondary' : '$textMuted';

        return (
          <XStack
            key={column.field}
            justifyContent={getColumnJustify(column.align)}
            alignItems="center"
            minHeight={44}
            paddingHorizontal="$2"
            paddingVertical="$2"
            gap="$2"
            {...getColumnLayoutStyle(column)}
          >
            <Text
              flex={1}
              minWidth={0}
              textAlign={column.align || 'left'}
              numberOfLines={1}
              {...getTypographyRoleProps('tableHeader')}
            >
              {column.label}
            </Text>
            {column.sortable ? (
              <Button
                chromeless
                circular
                size="$2"
                flexShrink={0}
                aria-label={sortButtonLabel}
                onPress={() => grid.toggleSort(column.field)}
                hoverStyle={{ backgroundColor: '$bgPage' }}
                pressStyle={{ backgroundColor: '$bgPanelElev' }}
                icon={ChevronIcon ? <ChevronIcon size="xs" color={iconColor} /> : undefined}
              />
            ) : null}
          </XStack>
        );
      })}
    </XStack>
  );
}

export function TableBodyView({ visible = true }) {
  const grid = useGridView();
  const bodyRef = useViewportTracking(visible);

  if (visible === false) {
    return null;
  }

  const activeColumns = grid.visibleColumns?.length ? grid.visibleColumns : grid.resolvedColumns;

  if (grid.error) {
    return (
      <YStack flex={1} alignItems="center" justifyContent="center" padding="$5">
        <Text color="$danger" fontWeight="600">{grid.error}</Text>
      </YStack>
    );
  }

  return (
    <ScrollView flex={1}>
      <YStack ref={bodyRef}>
        {grid.rows.map((row, index) => (
          <YStack key={row.id ?? index}>
            <XStack
              alignItems="stretch"
              paddingHorizontal="$2"
              backgroundColor={grid.selectedIds.has(row.id) ? '$accentBg' : index % 2 === 1 ? '$bgPage' : 'transparent'}
              hoverStyle={{ backgroundColor: '$bgPage' }}
            >
              {grid.selectable || grid.nested ? <UtilityCell rowId={row.id} /> : null}
              {activeColumns.map((column) => {
                const Renderer = column.renderer || DefaultGridCellRenderer;
                const cellValue = resolveCellValue(row, column);

                return (
                  <XStack
                    key={`${row.id}-${column.field}`}
                    alignItems="center"
                    justifyContent={getColumnJustify(resolveCellAlignment(column))}
                    paddingVertical="$3"
                    paddingHorizontal="$2"
                    minHeight={46}
                    {...getColumnLayoutStyle(column)}
                  >
                    <Renderer value={cellValue} row={row} column={column} grid={grid} />
                  </XStack>
                );
              })}
            </XStack>
            <Separator borderColor="$lineSubtle" />
          </YStack>
        ))}

        {!grid.rows.length && !grid.isLoading ? (
          <YStack minHeight={120} alignItems="center" justifyContent="center" padding="$5">
            <Text color="$textSecondary" fontWeight="600">No records available</Text>
            <Text color="$textMuted" fontSize="$3">There's nothing to show here yet.</Text>
          </YStack>
        ) : null}

        {grid.isLoading && !grid.rows.length ? (
          <YStack minHeight={64} padding="$4" gap="$2">
            {[0, 1, 2].map((i) => (
              <XStack key={i} height={46} borderRadius="$radiusMd" backgroundColor="$bgPage" />
            ))}
          </YStack>
        ) : null}
      </YStack>
    </ScrollView>
  );
}

export function TableFooter({ visible = true }) {
  const grid = useGridView();

  if (visible === false) {
    return null;
  }

  return (
    <XStack
      alignItems="center"
      justifyContent="space-between"
      gap="$3"
      paddingTop="$1"
      paddingRight="$3"
      paddingBottom="$1"
      paddingLeft="$3"
      minHeight={64}
      borderTopWidth={1}
      borderTopColor="$lineSubtle"
      backgroundColor="$bgPanel"
      flexWrap="wrap"
    >
      <Text color="$textMuted">
        {grid.total} records
      </Text>

      <PageNavBar
        outlined={false}
        label={`Page ${grid.currentPage} of ${grid.pageCount}`}
        onFirstPage={() => grid.setPage(1)}
        onPreviousPage={() => grid.setPage(grid.currentPage - 1)}
        onNextPage={() => grid.setPage(grid.currentPage + 1)}
        onLastPage={() => grid.setPage(grid.pageCount)}
        firstDisabled={grid.currentPage <= 1}
        previousDisabled={grid.currentPage <= 1}
        nextDisabled={grid.currentPage >= grid.pageCount}
        lastDisabled={grid.currentPage >= grid.pageCount}
      />
    </XStack>
  );
}
