import debug from 'debug';
import { isNil, lensPath, set, splitEvery, update } from 'ramda';
import { FC, useEffect, useMemo, useState } from 'react';
import tw, { css, styled } from 'twin.macro';
import { Borders, borders } from '../../constants/border';
import { useLedCount } from '../contents/led-count';
import { DisplayConfig, LedStripConfigOfBorders } from '../models/display-config';
import { LedStripConfig } from '../models/led-strip-config';
import { PixelRgb } from '../models/pixel-rgb';
import { ScreenshotDto } from '../models/screenshot.dto';
import { DraggableStrip } from './draggable-strip';
import { StyledPixel } from './styled-pixel';

export const logger = debug('app:completed-led-strip');

interface CompletedLedStripProps {
  screenshots: ScreenshotDto[];
  onDisplayConfigChange?: (value: DisplayConfig) => void;
}

type BorderLedStrip = {
  pixels: PixelRgb[];
  config: LedStripConfig | null;
};

const StyledContainer = styled.section(
  ({ rows, columns }: { rows: number; columns: number }) => [
    tw`grid m-4 pb-2 items-center justify-items-center select-none`,
    css`
      grid-template-columns: repeat(${columns}, 1fr);
      grid-template-rows: auto repeat(${rows}, 1fr);
    `,
  ],
);
const StyledCompletedContainer = styled.section(
  tw`dark:bg-transparent shadow-xl border-gray-500 border rounded-full flex flex-wrap justify-around items-center mb-2`,
  css`
    grid-column: 1 / -1;
    justify-self: stretch;
  `,
);

export const CompletedLedStrip: FC<CompletedLedStripProps> = ({
  screenshots,
  onDisplayConfigChange,
}) => {
  const borderLedStrips: BorderLedStrip[] = useMemo(() => {
    return screenshots.flatMap((ss) =>
      borders.map((b) => ({
        pixels: splitEvery(3, Array.from(ss.colors[b])) as PixelRgb[],
        config: ss.config.led_strip_of_borders[b],
      })),
    );
  }, [screenshots]);
  const ledCount = useMemo(
    () => borderLedStrips.reduce((prev, curr) => prev + curr.pixels.length, 0),
    [borderLedStrips],
  );

  const { setLedCount } = useLedCount();
  // setLedCount for context
  useEffect(() => {
    setLedCount(ledCount);
  }, [ledCount, setLedCount]);

  const [overrideBorderLedStrips, setOverrideBorderLedStrips] =
    useState<BorderLedStrip[]>();

  const completedPixels = useMemo(() => {
    const completed: PixelRgb[] = new Array(ledCount).fill([0, 0, 0]);
    (overrideBorderLedStrips ?? borderLedStrips).forEach(({ pixels, config }) => {
      if (isNil(config)) {
        return;
      }
      if (config.global_start_position <= config.global_end_position) {
        pixels.forEach((color, i) => {
          completed[config.global_start_position + i] = color;
        });
      } else {
        pixels.forEach((color, i) => {
          completed[config.global_start_position - i] = color;
        });
      }
    });

    return completed.map((color, i) => <StyledPixel rgb={color} key={i} />);
  }, [ledCount, borderLedStrips, overrideBorderLedStrips]);

  const strips = useMemo(() => {
    return borderLedStrips.map(({ config, pixels }, index) =>
      config ? (
        <DraggableStrip
          key={index}
          {...{ config, pixels, index: index + 1 }}
          onConfigChange={(c) => {
            setOverrideBorderLedStrips(
              update(index, { config: c, pixels }, borderLedStrips),
            );
          }}
          onConfigFinish={(c) => {
            const indexOfDisplay = Math.floor(index / borders.length);
            const xLens = lensPath<LedStripConfigOfBorders, Borders>([
              borders[index % borders.length],
            ]);
            const displayConfig: DisplayConfig = {
              ...screenshots[indexOfDisplay].config,
              led_strip_of_borders: set(
                xLens,
                c,
                screenshots[indexOfDisplay].config.led_strip_of_borders,
              ),
            };
            onDisplayConfigChange?.(displayConfig);
          }}
        />
      ) : (
        <div key={index} />
      ),
    );
  }, [borderLedStrips, screenshots]);

  useEffect(() => {
    setOverrideBorderLedStrips(undefined);
  }, [borderLedStrips]);
  return (
    <StyledContainer rows={screenshots.length * borders.length} columns={ledCount}>
      <StyledCompletedContainer>{completedPixels}</StyledCompletedContainer>
      {strips}
    </StyledContainer>
  );
};


