/* eslint-disable react-hooks/exhaustive-deps */
import { CompactSelection } from '@glideapps/glide-data-grid';
import React, { useEffect, useRef } from 'react';

import { useGridlerStore } from './Store';

//The computer component does not need to be recalculated on every render, so we use React.memo to prevent unnecessary re-renders.
export const Computer = React.memo(() => {
  const refFirstRun = useRef(0);
  const refLastFilters = useRef<any>(null);
  const {
    _glideref,
    _gridSelectionRows,
    askAPIRowNumber,
    colFilters,
    colOrder,
    colSize,
    colSort,
    columns,
    getState,
    loadPage,

    setState,
    setStateFN,
    values,
  } = useGridlerStore((s) => ({
    _glideref: s._glideref,
    _gridSelectionRows: s._gridSelectionRows,
    askAPIRowNumber: s.askAPIRowNumber,
    colFilters: s.colFilters,
    colOrder: s.colOrder,
    colSize: s.colSize,
    colSort: s.colSort,
    columns: s.columns,
    getState: s.getState,
    loadPage: s.loadPage,

    setState: s.setState,
    setStateFN: s.setStateFN,
    uniqueid: s.uniqueid,
    values: s.values,
  }));

  useEffect(() => {
    const searchSelection = async () => {
      const page_data = getState('_page_data');
      const pageSize = getState('pageSize');
      const keyField = getState('keyField') ?? 'id';
      const rowIndexes = [];
      for (const vi in values as Array<any>) {
        let rowIndex = -1;
        const key = String(
          typeof values?.[vi] === 'object'
            ? values?.[vi]?.[keyField]
            : typeof values?.[vi] === 'string'
              ? values?.[vi]
              : undefined
        );
        for (const p in page_data) {
          for (const r in page_data[p]) {
            const idx = Number(p) * pageSize + Number(r);

            if (String(page_data[p][r]?.[keyField]) === key) {
              //console.log('Found row S', idx, page_data[p][r], page_data[p][r]?.[keyField], key);
              rowIndex = idx;
              break;
            }
          }
          if (rowIndex >= 0) {
            rowIndexes.push(rowIndex);
            break;
          }
        }
        if (!(rowIndex >= 0) && typeof askAPIRowNumber === 'function') {
          const idx = await askAPIRowNumber(key);
          if (idx) {
            rowIndexes.push(idx);
          }
        }
      }

      return rowIndexes;
    };

    if (values) {
      searchSelection().then((rowIndexes) => {
        let rows = CompactSelection.empty();
        rowIndexes.forEach((r) => {
          rows = rows.add(r);
        });

        setStateFN('_gridSelectionRows', () => {
          return rows;
        });

        setStateFN('_gridSelection', (c) => ({
          columns: c?.columns ?? CompactSelection.empty(),
          ...c,
          rows,
        }));
      });
    }
  }, [values]);

  useEffect(() => {
    const onChange = getState('onChange');
    if (onChange && typeof onChange === 'function') {
      const page_data = getState('_page_data');
      const pageSize = getState('pageSize');

      const buffers = [];
      if (_gridSelectionRows) {
        for (const range of _gridSelectionRows) {
          let buffer = undefined;

          for (const p in page_data) {
            for (const r in page_data[p]) {
              const idx = Number(p) * pageSize + Number(r);
              if (isNaN(idx)) {
                continue;
              }

              if (Number(page_data[p][r]?._rownumber) === range + 1) {
                buffer = page_data[p][r];
                //console.log('Found row', range, idx, page_data[p][r]?._rownumber);
                break;
              } else if (idx === range + 1) {
                buffer = page_data[p][r];
                //console.log('Found row 2', range, idx, page_data[p][r]?._rownumber);
                break;
              }
            }
          }
          if (buffer !== undefined) {
            buffers.push(buffer);
          }
        }
      }

      const _values = getState('values');

      if (JSON.stringify(_values) !== JSON.stringify(buffers)) {
        onChange(buffers);
      }
    }
  }, [JSON.stringify(_gridSelectionRows), getState]);

  useEffect(() => {
    setState(
      'renderColumns',
      columns?.map((c) => ({
        ...c,
        hasMenu: c?.hasMenu ?? true,
        icon: 'sort',
      }))
    );
  }, [columns]);

  useEffect(() => {
    if (!colSort) {
      return;
    }

    setState('_gridSelection', {
      columns: CompactSelection.empty(),
      current: undefined,
      rows: CompactSelection.empty(),
    });

    setState('_gridSelectionRows', CompactSelection.empty());
    setStateFN('renderColumns', (cols) => {
      return cols?.map((c) => ({
        ...c,
        icon:
          c.id && colSort?.find((col) => col.id === c.id)?.direction
            ? colSort?.find((col) => col.id === c.id)?.direction === 'asc'
              ? 'sortup'
              : 'sortdown'
            : (c.defaultIcon ?? 'sort'),
      }));
    }).then(() => {
      loadPage(0, 'all');
    });
  }, [colSort]);

  useEffect(() => {
    if (!colFilters) {
      return;
    }

    if (JSON.stringify(refLastFilters.current) !== JSON.stringify(colFilters)) {
      loadPage(0, 'all');
      refLastFilters.current = colFilters;
    }
  }, [colFilters]);

  useEffect(() => {
    if (!colSize) {
      return;
    }
    setStateFN('renderColumns', (cols) => {
      return cols?.map((c) => ({
        ...c,
        width: c.id && colSize?.[c.id] ? colSize?.[c.id] : c.width,
      }));
    });
  }, [colSize]);

  useEffect(() => {
    if (!colOrder) {
      return;
    }

    setStateFN('renderColumns', (cols) => {
      const result = cols?.sort((a, b) => {
        if (colOrder[a.id] > colOrder[b.id]) {
          return 1;
        }
        return -1;
      });

      return result;
    });
  }, [colOrder]);

  useEffect(() => {
    if (!_glideref) {
      return;
    }
    if (refFirstRun.current > 0) {
      return;
    }
    refFirstRun.current = 1;
    loadPage(0);
  }, [_glideref]);

  // console.log('Gridler:Debug:Computer', {
  //   colFilters,
  //   colOrder,
  //   colSize,
  //   colSort,
  //   columns,
  //   uniqueid
  // });

  return <></>;
});
