/**
 * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
 */
import {useEffect, useState} from 'react';

import {
  DataRowType,
  Table,
  TableHeaderKey,
  ITable,
  ITableWithPaginationHeader,
  ITableSort
} from 'components/table';
import {isEqual} from 'utility/validators';
import SearchInput from 'components/forms/SearchInput';
import {compare} from 'utility/sort';
import {TableScreenHeader} from 'components/table-screen-header/table-screen-header';
import {AddButton} from 'components/buttons/icon-buttons';
import {Pagination} from 'components/pagination/pagination' ;
import {Select} from 'components/ui/select';

import {useSort, useSearch} from 'utility/custom-hooks';

interface ITableWithPagination extends ITable {
  screenHeader: ITableWithPaginationHeader;
  paginationItemText?: string;
  getCurrentDisplayList?: (data: Record<string, string | number | null>[]) => void;
}

const TableWithPagination = ({
  title = '',
  screenHeader,
  columns,
  data,
  sortColumn,
  sortDirection,
  style,
  paginationItemText,
  errorMessage,
  getCurrentDisplayList,
  changeSortProps,
  searchValue: propsSearchValue = '',
  changeSearch
}: ITableWithPagination): JSX.Element => {
  const [currentPageNumber, setCurrentPageNumber] = useState<number>(1);
  const [currentData, setCurrentData] = useState<DataRowType[]>([]);
  const [filteredData, setFilteredData] = useState<DataRowType[]>(data || []);
  const [total, setTotal] = useState<number>(data ? data.length : 0);
  const [rowsCount, setRowsCount] = useState(10);
  const [sortData, setSortData] = useSort({
    sortColumn,
    sortDirection
  });
  const [searchValue, setSearchValue] = useSearch(propsSearchValue);
  const amendMarginsInElementsHeight = (selector: string, action: 'add' | 'remove') => {
    const element = document.querySelector(selector);
    let elementHeight = element?.clientHeight || 0;

    if (!element) {
      return;
    }

    if (action === 'add') {
      elementHeight += parseInt(window?.getComputedStyle(element).getPropertyValue('margin-top'));
      elementHeight += parseInt(window?.getComputedStyle(element).getPropertyValue('margin-bottom'));
    } else {
      elementHeight -= parseInt(window?.getComputedStyle(element).getPropertyValue('margin-top'));
      elementHeight -= parseInt(window?.getComputedStyle(element).getPropertyValue('margin-bottom'));
    }

    return elementHeight;
  };

  const calculateRowsCount = () => {
    const tableContainerHeight = amendMarginsInElementsHeight('.table-container', 'remove') || 0;
    const paginationHeight = amendMarginsInElementsHeight('.pagination-container', 'add') || 0;
    const tableHeaderHeight = amendMarginsInElementsHeight('.table-header', 'add') || 0;
    const tableRow = document.querySelector('.table-row') || {clientHeight: 50};
    const rowHeight = tableRow?.clientHeight || 50;
    const newRowsCount = Math.round((tableContainerHeight - paginationHeight - tableHeaderHeight) / rowHeight);

    setRowsCount(newRowsCount || rowsCount);
  };

  useEffect(() => {
    let pxRatioBeforeZoom = window.devicePixelRatio;
    let windowHeightBeforeResize = window.innerHeight;
    const trackResize = e => {
      const pxRatioAfterZoom = e.devicePixelRatio;
      const windowHeightAfterResize = e.target.innerHeight;

      if (pxRatioAfterZoom !== pxRatioBeforeZoom || windowHeightAfterResize !== windowHeightBeforeResize) {
        pxRatioBeforeZoom = pxRatioAfterZoom;
        windowHeightBeforeResize = windowHeightAfterResize;

        calculateRowsCount();
      }
    };

    calculateRowsCount();

    window.addEventListener('resize', trackResize);

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

  useEffect(() => {
    let newData = Array.isArray(data) ? [...data] : [];

    if (searchValue && Array.isArray(data)) {
      newData = data.filter(prop => {
        return Object.keys(columns).some(key => {
          return String(prop[key]).toLowerCase().includes(searchValue.toLowerCase());
        });
      });
    }

    if (!isEqual(newData, filteredData)) {
      setFilteredData(newData);
    }

    if (!isEqual(total, newData.length)) {
      setTotal(newData.length);
    }
  }, [data, searchValue, rowsCount, columns]);

  useEffect(() => {
    const start = (currentPageNumber - 1) * rowsCount;
    const sortedData = sortData
      ? filteredData.sort((a, b) => compare(a, b, sortData.sortDirection, sortData.sortColumn))
      : filteredData;
    const newCurrentData = sortedData.slice(start, start + rowsCount);

    if (!isEqual(newCurrentData, currentData)) {
      setCurrentData(newCurrentData);

      if (getCurrentDisplayList) {
        getCurrentDisplayList(newCurrentData);
      }
    }
  }, [filteredData, currentPageNumber, rowsCount, sortData]);

  const search = (val: string) => {
    if (val !== searchValue) {
      if (changeSearch) {
        changeSearch({searchValue: val});
      } else {
        setSearchValue(val);
      }

      setCurrentPageNumber(1);
    }
  };

  const sort = (data: ITableSort) => {
    if (changeSortProps) {
      changeSortProps(data);
    } else {
      setSortData(data);
    }
  };

  const renderControl = (screenHeader: ITableWithPaginationHeader, key: TableHeaderKey) => {
    switch (key) {
      case TableHeaderKey.Search:
        return <SearchInput search={search} defaultValue={searchValue} />;
      case TableHeaderKey.AddRow:
        return <AddButton onClick={screenHeader[key]?.openAddRowModal} className="testId-hashAddButton" />;
      case TableHeaderKey.SelectType:
        return <Select {...screenHeader[key]} />;
      default:
        return null;
    }
  };

  return (
    <>
      <TableScreenHeader
        title={title}
        screenHeader={screenHeader}
        renderControl={renderControl}
      />
      <Table
        columns={columns}
        data={currentData}
        sortColumn={sortColumn}
        sortDirection={sortDirection}
        style={style}
        sort={sort}
        errorMessage={errorMessage}
      />
      <Pagination
        currentPageNumber={currentPageNumber}
        setCurrentPage={setCurrentPageNumber}
        numberOfItems={total}
        itemsPerPage={rowsCount}
        itemText={paginationItemText}
      />
    </>
  );
};

export default TableWithPagination;