import React, { useEffect, useState, useMemo } from 'react';
import { CustomLine } from './CustomLine';
import { PaohvisDataPaginated, RowInformation, LinesHyperEdges } from '../types';
import { ArrowDownward, ArrowUpward, ContactPageSharp, Sort } from '@mui/icons-material';
import { select } from 'd3';
import { visualizationColors, tailwindColors } from 'config';

interface HyperEdgeRangesBlockProps {
  dataModel: PaohvisDataPaginated;
  dataLinesHyperedges: LinesHyperEdges[];
  rowHeight: number;
  yOffset: number;
  rowLabelColumnWidth: number;
  classTopTextColumns: string;
  currentPageRows?: {
    startIndexRow: number;
    endIndexRow: number;
  } | null;
  onMouseEnterHyperEdge: (event: React.MouseEvent<SVGGElement, MouseEvent>) => void;
  onMouseLeaveHyperEdge: () => void;
  rowsMaxPerPage: number;
  marginText: number;
  sortState: string;
  numRows: number;
  columnHeaderInformation: RowInformation;
  widthColumns: number;
  headerState: string;
  configStyle: { [key: string]: string };
  handleClickHeaderSorting: (event: React.MouseEvent<SVGGElement, MouseEvent>) => void;
}

export const HyperEdgeRangesBlock: React.FC<HyperEdgeRangesBlockProps> = ({
  dataModel,
  dataLinesHyperedges,
  rowHeight,
  yOffset,
  rowLabelColumnWidth,
  classTopTextColumns,
  currentPageRows,
  rowsMaxPerPage,
  marginText,
  widthColumns,
  configStyle,
  numRows,
  sortState,
  headerState,
  columnHeaderInformation,
  onMouseEnterHyperEdge,
  onMouseLeaveHyperEdge,
  handleClickHeaderSorting,
}) => {
  const accumulatedWidthHeaders = useMemo(() => {
    const accumulatedWidths: number[] = [0];
    let sum = 0;

    columnHeaderInformation.forEach((column, index) => {
      sum += column.width;
      if (index !== columnHeaderInformation.length - 1) {
        accumulatedWidths.push(sum);
      }
    });

    return accumulatedWidths;
  }, [columnHeaderInformation]);
  const adjustedFontSize = useMemo(() => {
    // text-sm: 0.75 rem, rowHeight: 20
    return Math.max(0.4, (rowHeight * 0.75) / 20);
  }, [rowHeight]);

  const [isHovered, setIsHovered] = useState(false);
  const [hoverRowIndex, setHoverRowIndex] = useState<number | null>(null);
  const [iconComponents, setIconComponents] = useState<{ [key: number]: JSX.Element }[]>(Array(columnHeaderInformation.length).fill({}));
  const [iconColors, setIconColors] = useState<string[]>([]);

  useEffect(() => {
    const iconColorsTemporal: string[] = [];

    const updatedIconComponents = columnHeaderInformation.map((row, indexRows) => {
      let iconComponent: JSX.Element = <></>;
      if (row.header == headerState) {
        switch (sortState) {
          case 'asc':
            iconComponent = <ArrowUpward />;
            break;
          case 'desc':
            iconComponent = <ArrowDownward />;
            break;
          case 'original':
            iconComponent = <Sort />;

            break;
          default:
            iconComponent = <></>;
        }
        iconColorsTemporal.push('hsl(var(--clr-sec--800))');
      } else {
        iconComponent = <></>;
        iconColorsTemporal.push('hsl(var(--clr-sec--500))');
      }

      if (indexRows == hoverRowIndex && headerState != row.header) {
        iconComponent = <Sort />;
      }
      return { [indexRows]: iconComponent };
    });

    setIconColors(iconColorsTemporal);
    setIconComponents(updatedIconComponents);
  }, [sortState, headerState, hoverRowIndex]);

  return (
    <>
      <g key={'hyperEdgeInformationTop'} className="hyperEdgeInformation">
        <g key={'hyperEdgeLinesRows'} transform={`translate(${rowLabelColumnWidth},${yOffset})`}>
          {[...Array(numRows)].map((_, i) => (
            <React.Fragment key={`horizontalLineRows-${i}`}>
              {i === 0 && (
                <CustomLine
                  key={`horizontalLineRowsTop-${i}`}
                  className={`horizontalLineRowsTop-${i}`}
                  x1={0}
                  x2={dataModel.pageData.hyperEdgeRanges.length * rowHeight}
                  y1={-yOffset}
                  y2={-yOffset}
                  strokeWidth={0.025 * rowHeight}
                  fill={configStyle.colorLinesGrid}
                />
              )}
              {i === numRows - 1 && (
                <CustomLine
                  key={`horizontalLineRowsExtra-${i}`}
                  x1={0}
                  x2={dataModel.pageData.hyperEdgeRanges.length * rowHeight}
                  y1={rowHeight * (i + 1)}
                  y2={rowHeight * (i + 1)}
                  strokeWidth={0.025 * rowHeight}
                  fill={configStyle.colorLinesGrid}
                />
              )}

              <CustomLine
                key={`horizontalLineRowsBottom-${i}`}
                x1={0}
                x2={dataModel.pageData.hyperEdgeRanges.length * rowHeight}
                y1={rowHeight * i}
                y2={rowHeight * i}
                strokeWidth={0.025 * rowHeight}
                fill={configStyle.colorLinesGrid}
              />
            </React.Fragment>
          ))}
        </g>
        <g
          key={'hyperEdgeInformation'}
          className="hyperEdgeInformation text-columns "
          transform={'translate(' + rowLabelColumnWidth + ',' + widthColumns + ')'}
        >
          {columnHeaderInformation[0] &&
            columnHeaderInformation[0].data.map((rowLabel, indexRows) => (
              <g
                key={'colsLabel col-' + indexRows}
                className={'colsLabel col-' + indexRows}
                transform={'translate(' + indexRows * rowHeight + ',0)rotate(-90,0,0)'}
              >
                {columnHeaderInformation.map((row, index) => (
                  <g key={'text-col-' + index} transform={'translate(' + (accumulatedWidthHeaders[index] + rowHeight) + ',0)'}>
                    {row.data[indexRows] !== undefined &&
                    row.data[indexRows] !== '' &&
                    (typeof row.data[indexRows] !== 'object' || Array.isArray(row.data[indexRows])) ? (
                      <>
                        <foreignObject x="0" y="0" width={0 === index ? row.width + rowHeight : row.width} height={rowHeight}>
                          <div className="w-full h-full flex justify-center items-start">
                            <span
                              className={`${classTopTextColumns}`}
                              style={{
                                fontSize: `${adjustedFontSize}rem`,
                              }}
                            >
                              {row.data[indexRows].toString()}
                            </span>
                          </div>
                        </foreignObject>
                      </>
                    ) : (
                      <rect
                        width={0 === index ? row.width + rowHeight : row.width}
                        height={rowHeight}
                        fill={'url(#diagonal-lines)'}
                        strokeWidth={0}
                      ></rect>
                    )}
                  </g>
                ))}
              </g>
            ))}
        </g>

        <g
          key={'columnInformationHeaders'}
          className={'columnInformationHeaders'}
          transform={'translate(' + (rowLabelColumnWidth - rowHeight) + ',' + widthColumns + ')'}
        >
          {columnHeaderInformation.map((headerData, headerIndex) => (
            <g
              key={'gHeadersColumns-' + headerIndex}
              className={`headersCols-${headerData.header} cursor-pointer`}
              transform={'translate(' + 0 + ',' + (-accumulatedWidthHeaders[headerIndex] - rowHeight) + ')rotate(-90, 0,0)'}
              onClick={(event) => {
                handleClickHeaderSorting(event);
              }}
              onMouseEnter={(event) => {
                setHoverRowIndex(headerIndex);
                setIsHovered(true);
                select(event.currentTarget).select('rect').attr('fill', 'hsl(var(--clr-sec--300))');
              }}
              onMouseLeave={(event) => {
                setIsHovered(sortState !== 'original');
                setHoverRowIndex(null);
                select(event.currentTarget).select('rect').attr('fill', 'hsl(var(--clr-sec--200))');
              }}
            >
              <rect
                width={0 === headerIndex ? headerData.width + rowHeight : headerData.width}
                height={rowHeight}
                fill={'hsl(var(--clr-sec--200))'}
                opacity={1.0}
                strokeWidth={0}
              ></rect>

              <foreignObject x="0" y="0" width={headerData.width} height={rowHeight}>
                <div className="w-full h-full flex justify-left">
                  <span className={`${classTopTextColumns}`} style={{ fontSize: `${adjustedFontSize}rem` }}>
                    {headerData.header !== undefined && (typeof headerData.header !== 'object' || Array.isArray(headerData.header))
                      ? (headerData.header as any).toString()
                      : ' '}
                  </span>
                </div>
              </foreignObject>
              {iconComponents[headerIndex] && isHovered && (
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  width={2 * headerData.width - rowHeight}
                  height={rowHeight}
                  style={{ color: iconColors[headerIndex], stroke: 'none' }}
                >
                  {iconComponents[headerIndex][headerIndex]}
                </svg>
              )}
              <CustomLine
                x1={headerData.width}
                x2={headerData.width}
                y1={0}
                y2={rowHeight * (dataModel.pageData.hyperEdgeRanges.length + 1)}
                strokeWidth={0.025 * rowHeight}
                fill={configStyle.colorLinesGrid}
              />
            </g>
          ))}
        </g>
        {dataModel.pageData.hyperEdgeRanges.map((hyperEdgeRange, indexHyperEdgeRange) => (
          <React.Fragment key={indexHyperEdgeRange}>
            <g
              className={'hyperEdgeBlockLinesRef hyperEdgeLines-col-' + indexHyperEdgeRange}
              transform={'translate(' + (rowLabelColumnWidth + indexHyperEdgeRange * rowHeight) + ',' + widthColumns + ')rotate(-90,0,0)'}
            >
              <CustomLine
                x1={-rowHeight * numRows}
                x2={indexHyperEdgeRange === 0 ? 0 : yOffset}
                y1={0}
                y2={0}
                strokeWidth={0.025 * rowHeight}
                fill={configStyle.colorLinesGrid}
              />
            </g>
            {indexHyperEdgeRange === dataModel.pageData.hyperEdgeRanges.length - 1 && (
              <g
                key={'hyperEdgeBlockLinesRef-' + indexHyperEdgeRange}
                className={'hyperEdgeBlockLinesRef hyperEdgeLines-col-' + indexHyperEdgeRange}
                transform={
                  'translate(' +
                  (rowLabelColumnWidth + (dataModel.pageData.hyperEdgeRanges.length - 1) * rowHeight) +
                  ',' +
                  widthColumns +
                  ')rotate(-90,0,0)'
                }
              >
                <CustomLine
                  x1={-rowHeight * numRows}
                  x2={yOffset}
                  y1={rowHeight}
                  y2={rowHeight}
                  strokeWidth={0.025 * rowHeight}
                  fill={configStyle.colorLinesGrid}
                />
              </g>
            )}
          </React.Fragment>
        ))}

        {dataModel.pageData.hyperEdgeRanges.map((hyperEdgeRange, indexHyperEdgeRange) => (
          <React.Fragment key={`fragment-${indexHyperEdgeRange}`}>
            <g
              className={'hyperEdgeBlock hyperEdge-col-' + indexHyperEdgeRange}
              key={'hyperEdgeBlockddd hyperEdge-col-' + indexHyperEdgeRange}
              onMouseEnter={onMouseEnterHyperEdge}
              onMouseLeave={onMouseLeaveHyperEdge}
            >
              <g
                key={'groupBlockExtra-' + indexHyperEdgeRange}
                transform={`translate(${rowLabelColumnWidth + indexHyperEdgeRange * rowHeight + 0.5 * rowHeight},${yOffset + 0.5 * rowHeight})`}
              >
                {currentPageRows && dataLinesHyperedges[indexHyperEdgeRange]?.valid && (
                  <CustomLine
                    key={'hyperRangeBlockLine line_' + indexHyperEdgeRange}
                    x1={0}
                    y1={(dataLinesHyperedges[indexHyperEdgeRange].y0 - currentPageRows.startIndexRow) * rowHeight}
                    x2={0}
                    y2={(dataLinesHyperedges[indexHyperEdgeRange].y1 - currentPageRows.startIndexRow) * rowHeight}
                    strokeWidth={0.075 * rowHeight}
                    fill={visualizationColors.GPNeutral.colors[1][0]}
                  />
                )}
              </g>

              <g
                className={'hyperEdgeBlockCircles'}
                key={'hyperEdgeBlockCircles-' + indexHyperEdgeRange}
                transform={`translate(${rowLabelColumnWidth + indexHyperEdgeRange * rowHeight + 0.5 * rowHeight},${yOffset + 0.5 * rowHeight})`}
              >
                {currentPageRows &&
                  hyperEdgeRange.hyperEdges.indices
                    .filter((valueIndex) => valueIndex >= currentPageRows.startIndexRow && valueIndex < currentPageRows.endIndexRow)
                    .map((valueIndex: number, indexColumn: number) => (
                      <circle
                        key={'circleBlock-' + valueIndex + '_' + indexColumn}
                        className={`circle-${valueIndex}`}
                        cx={0}
                        cy={(valueIndex - currentPageRows.startIndexRow) * rowHeight}
                        r={rowHeight * 0.25}
                        fill="white"
                        strokeWidth={0.025 * rowHeight}
                        stroke="black"
                      />
                    ))}
              </g>
            </g>
          </React.Fragment>
        ))}
      </g>
    </>
  );
};