import React, { useCallback, useRef } from 'react';
import { Platform } from 'react-native';
import ReactNativeStraightTableViewManager from '../specs/SimpleGridNativeComponent';
import { useSetAtom } from 'jotai';
import {
  setDragBoxAtom,
  setExpandedCellAtom,
  setSearchingTableColumnAtom,
} from '../atoms';
import CarbonTheme from '@qlik/react-native-carbon/src/core/CarbonTheme';
import type {
  ColumnHeader,
  Cols,
  DragBoxEvent,
  EndReachedEvent,
  ExpandCellEvent,
  GrandTotalCell,
  HeaderPressedEvent,
  Layout,
  SearchColumnEvent,
  SelectionsChangedEvent,
  SimpleGridProps,
  TableData,
  Totals,
} from './SimpleGrid.types';

export type { SimpleGridLayout, SimpleGridProps } from './SimpleGrid.types';

const clampColorChannel = (value: number) =>
  Math.max(0, Math.min(255, Math.round(value)));

const toHexChannel = (value: number) =>
  clampColorChannel(value).toString(16).padStart(2, '0').toUpperCase();

const normalizeColor = (value?: string | null) => {
  if (!value || typeof value !== 'string') {
    return undefined;
  }

  try {
    const trimmedValue = value.trim();
    const rgbaMatch = trimmedValue.match(
      /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*([\d.]+))?\s*\)$/i
    );

    if (!rgbaMatch) {
      return trimmedValue;
    }

    const [, red, green, blue, alpha] = rgbaMatch;
    const hexRed = toHexChannel(Number(red));
    const hexGreen = toHexChannel(Number(green));
    const hexBlue = toHexChannel(Number(blue));

    if (alpha === undefined) {
      return `#${hexRed}${hexGreen}${hexBlue}`;
    }

    const normalizedAlpha = Number(alpha);
    const alphaValue = Number.isFinite(normalizedAlpha)
      ? Math.max(0, Math.min(1, normalizedAlpha)) * 255
      : 255;
    const hexAlpha = toHexChannel(alphaValue);

    return `#${hexAlpha}${hexRed}${hexGreen}${hexBlue}`;
  } catch (error) {
    // Fallback if color parsing fails
    return undefined;
  }
};

const resolveLayoutBackgroundColor = (layout: Layout) => {
  try {
    const generalComponent = layout.components?.find(
      component => component.key === 'general'
    );
    const bgColor = generalComponent?.bgColor;

    if (!bgColor) {
      return undefined;
    }

    if (bgColor.useColorExpression && bgColor.colorExpression) {
      const colorExpression = String(bgColor.colorExpression);
      return normalizeColor(colorExpression);
    }

    const color = String(bgColor.color);
    return normalizeColor(color);
  } catch (error) {
    return undefined;
  }
};

const transformTotals = (
  layout: Layout,
  table: TableData
): Totals | undefined => {
  let totals;
  let rowIndex = 0;
  let values = table?.columns?.map((col: ColumnHeader, index: number) => {
    if (col.isDim && index === 0) {
      return layout.totals.label || 'Totals';
    }
    if (!col.isDim && rowIndex < layout.qHyperCube.qGrandTotalRow.length) {
      return layout.qHyperCube.qGrandTotalRow[rowIndex++].qText;
    }
    return '';
  });

  const rawTotalsPosition = table?.totalsPosition;
  const totalsPosition =
    rawTotalsPosition === 'top' || rawTotalsPosition === 'bottom'
      ? rawTotalsPosition
      : 'noTotals';
  const hasGrandTotals = (layout?.qHyperCube?.qGrandTotalRow?.length ?? 0) > 0;
  const shouldBuildTotals = hasGrandTotals && totalsPosition !== 'noTotals';
  const show = shouldBuildTotals;
  if (shouldBuildTotals) {
    totals = {
      label: layout.totals.label,
      position: totalsPosition,
      rows: layout.qHyperCube.qGrandTotalRow as ReadonlyArray<GrandTotalCell>,
      show,
      values: values as ReadonlyArray<string>,
    };
  }
  if (layout.qHyperCube?.qGrandTotalRow?.length === 0) {
    totals = undefined;
  }
  return totals;
};

const SimpleGrid: React.FC<SimpleGridProps> = ({
  contentStyle,
  clearSelections,
  layout,
  model,
  name,
  rect,
  style,
  tableData,
  theme,
  themeData,
  translations,
  onConfirmSelections,
  onEndReached,
  onHeaderPressed,
  onSelectionsChanged,
}) => {
  const draggingBox = useSetAtom(setDragBoxAtom);
  const expandCell = useSetAtom(setExpandedCellAtom);
  const searchColumn = useSetAtom(setSearchingTableColumnAtom);
  const carbonTheme = useRef<CarbonTheme>(
    new CarbonTheme({ theme: themeData })
  );

  const signalSearch = useCallback(
    async (column: ColumnHeader) => {
      try {
        if (column.dataColIdx === undefined) return;

        const props = await model.getEffectiveProperties();
        if (
          props?.qHyperCubeDef?.qDimensions[column.dataColIdx].qDef
            .qFieldDefs?.[0]
        ) {
          column.qCardinal =
            layout.qHyperCube.qDimensionInfo[column.dataColIdx].qCardinal;
          column.label =
            props?.qHyperCubeDef?.qDimensions[
              column.dataColIdx
            ].qDef.qFieldDefs?.[0];
          const fieldLabel =
            props?.qHyperCubeDef?.qDimensions[column.dataColIdx].qDef
              .qFieldLabels?.[0];
          column.display =
            !fieldLabel || fieldLabel.length === 0 ? column.label : fieldLabel;
          const qFallbackTitle =
            layout?.qHyperCube?.qDimensionInfo[column.dataColIdx]
              ?.qFallbackTitle;
          if (qFallbackTitle && qFallbackTitle.length > 0) {
            column.display = qFallbackTitle;
          }
        } else {
          const qDimInfo = layout.qHyperCube.qDimensionInfo[column.dataColIdx];
          const groupFieldDef = qDimInfo.qGroupFieldDefs?.[0];
          if (groupFieldDef && groupFieldDef.length > 0) {
            column.label = groupFieldDef;
          } else {
            column.label = qDimInfo.qFallbackTitle;
          }
          column.display = qDimInfo.qFallbackTitle;
        }
        searchColumn({ searching: true, column });
      } catch (error) { }
    },
    [model, searchColumn, layout]
  );

  // Unique key ensures React treats different tables as different component instances
  // This resets all React-side state (refs, callbacks, etc.) when switching tables
  const tableId = layout?.qInfo?.qId || 'default';
  const rawLiveTotalsPosition = tableData?.totalsPosition;
  const liveTotalsPosition =
    rawLiveTotalsPosition === 'top' || rawLiveTotalsPosition === 'bottom'
      ? rawLiveTotalsPosition
      : 'noTotals';
  const tableKey = `${tableId}-${liveTotalsPosition}`;
  const totals = transformTotals(layout, tableData);

  const cols: Cols = {
    header: tableData?.columns,
    footer: totals ? layout.qHyperCube.qGrandTotalRow : undefined,
    totals,
  };

  const rows = {
    rowsJSON: JSON.stringify(tableData?.rows || []),
    reset: tableData?.reset,
  };

  const resolvedLayoutBackgroundColor = resolveLayoutBackgroundColor(layout);

  // Helper to safely extract string values from theme
  const safeGetThemeColor = (path: string, defaultValue: string | null) => {
    try {
      const value = carbonTheme?.current?.getValue(path, defaultValue);
      return typeof value === 'string' ? value : defaultValue;
    } catch (error) {
      return defaultValue;
    }
  };

  const themeProps = {
    ...theme,
    headerBackgroundColor: normalizeColor(
      safeGetThemeColor('object.straightTable.header.backgroundColor', '#F0F0F0')
    ),
    backgroundColor:
      resolvedLayoutBackgroundColor ?? 'white',
    even:
      normalizeColor(
        safeGetThemeColor('object.straightTable.mobile.rows.even.backgroundColor', null)
      ) ?? undefined,
  };

  const handleConfirmSelections = useCallback(() => {
    try {
      onConfirmSelections?.();
    } catch (error) { }
  }, [onConfirmSelections]);

  const handleEndReached = useCallback(
    (event: EndReachedEvent) => {
      try {
        onEndReached?.(event);
      } catch (error) { }
    },
    [onEndReached]
  );

  const handleHeaderPressed = useCallback(
    (event: HeaderPressedEvent) => {
      try {
        onHeaderPressed?.(event);
      } catch (error) { }
    },
    [onHeaderPressed]
  );

  const handleSearchColumn = useCallback(
    (event: SearchColumnEvent) => {
      try {
        const column = JSON.parse(event.nativeEvent.column);
        signalSearch(column);
      } catch (error) { }
    },
    [signalSearch]
  );

  const handleSelectionsChanged = useCallback(
    (event: SelectionsChangedEvent) => {
      try {
        if (Platform.OS === 'ios') {
          const selections = JSON.parse(event.nativeEvent.selections);
          // Call the consumer's callback with parsed selections in nativeEvent
          if (onSelectionsChanged) {
            onSelectionsChanged({ nativeEvent: { selections } });
          }

          return;
        }
        onSelectionsChanged(event);
      } catch (error) { }
    },
    [onSelectionsChanged]
  );

  const onDragBox = useCallback(
    (event: DragBoxEvent) => {
      try {
        draggingBox({ dragging: event.nativeEvent.dragging });
      } catch (error) { }
    },
    [draggingBox]
  );

  const onExpandCell = useCallback(
    (event: ExpandCellEvent) => {
      try {
        const row = JSON.parse(event.nativeEvent.row);
        const col = JSON.parse(event.nativeEvent.col);
        expandCell({
          expand: true,
          data: { row, col },
          titles: translations.headerValues,
          viewData: layout?.isDataView,
        });
      } catch (error) { }
    },
    [expandCell, layout?.isDataView, translations.headerValues]
  );

  return (
    <ReactNativeStraightTableViewManager
      key={tableKey}
      cellContentStyle={contentStyle.cellStyle}
      clearSelections={clearSelections}
      cols={cols}
      containerWidth={rect.width}
      freezeFirstColumn={layout?.scrolling?.keepFirstColumnInView}
      headerContentStyle={contentStyle.headerStyle}
      isDataView={layout?.isDataView}
      name={name}
      rows={rows}
      size={layout.qHyperCube.qSize}
      style={style.table}
      theme={themeProps}
      translations={translations}
      onConfirmSelections={handleConfirmSelections}
      onDragBox={onDragBox}
      onEndReached={handleEndReached}
      onExpandCell={onExpandCell}
      onHeaderPressed={handleHeaderPressed}
      onSearchColumn={handleSearchColumn}
      onSelectionsChanged={handleSelectionsChanged}
    />
  );
};

export default SimpleGrid;
