import { invoke } from '@tauri-apps/api';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import tw, { styled } from 'twin.macro';
import { useAsync, useAsyncCallback } from 'react-async-hook';
import { DisplayWithLedStrips } from './components/display-with-led-strips';
import { PickerConfiguration } from './models/picker-configuration';
import { DisplayConfig } from './models/display-config';
import { ScreenshotDto } from './models/screenshot.dto';
import { Alert, Fab, Snackbar } from '@mui/material';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faRotateBack, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { update } from 'ramda';
import { CompletedLedStrip } from './components/completed-led-strip';
import { LedCountProvider } from './contents/led-count';
import debug from 'debug';
import { useSnackbar } from 'notistack';
import { fillParentCss } from '../styles/fill-parent';

const logger = debug('app:configurator');

const getPickerConfig = () => invoke<PickerConfiguration>('get_picker_config');
const getScreenshotOfDisplays = () =>
  invoke<ScreenshotDto[]>('take_snapshot').then((items) => {
    return items;
  });
const getScreenshotByConfig = async (config: DisplayConfig) => {
  return await invoke<ScreenshotDto>('get_screenshot_by_config', {
    config,
  });
};
const writePickerConfig = async (config: PickerConfiguration) => {
  return await invoke<void>('write_picker_config', {
    config,
  });
};
const StyledConfiguratorContainer = styled.section(
  tw`flex flex-col items-stretch relative overflow-hidden`,
  fillParentCss,
);

const StyledDisplayContainer = styled.section(tw`overflow-auto`);

const ConfiguratorInner: FC = () => {
  const { enqueueSnackbar } = useSnackbar();
  const { loading: pendingPickerConfig, result: savedPickerConfig } = useAsync(
    getPickerConfig,
    [],
  );

  const { loading: pendingScreenshotOfDisplays, result: defaultScreenshotOfDisplays } =
    useAsync(getScreenshotOfDisplays, []);

  const [screenshotOfDisplays, setScreenshotOfDisplays] = useState<ScreenshotDto[]>([]);

  const { loading: pendingGetLedColorsByConfig, execute: onDisplayConfigChange } =
    useAsyncCallback(async (value: DisplayConfig) => {
      const screenshot = await getScreenshotByConfig(value);
      setScreenshotOfDisplays((old) => {
        const index = old.findIndex((it) => it.config.id === screenshot.config.id);
        const newValue = update(index, screenshot, old);
        savedPickerConfig &&
          writePickerConfig({
            ...savedPickerConfig,
            display_configs: newValue.map((it) => it.config),
          });
        return newValue;
      });
    });

  const [displayConfigs, setDisplayConfigs] = useState<DisplayConfig[]>([]);

  useEffect(() => {
    const displayConfigs = savedPickerConfig?.display_configs;
    if (displayConfigs && defaultScreenshotOfDisplays) {
      setDisplayConfigs(displayConfigs);
      setScreenshotOfDisplays(defaultScreenshotOfDisplays);
      (async () => {
        for (const config of displayConfigs) {
          await onDisplayConfigChange(config);
        }
      })().then();
    }
  }, [savedPickerConfig, onDisplayConfigChange, defaultScreenshotOfDisplays]);

  const resetBackToDefaultConfig = useCallback(() => {
    if (defaultScreenshotOfDisplays) {
      setScreenshotOfDisplays(defaultScreenshotOfDisplays);
    } else {
      enqueueSnackbar('Default Config was not found. please try again later.', {
        variant: 'error',
      });
    }
  }, [setScreenshotOfDisplays, defaultScreenshotOfDisplays]);

  const displays = useMemo(() => {
    if (screenshotOfDisplays) {
      return screenshotOfDisplays.map((screenshot, index) => (
        <DisplayWithLedStrips
          key={index}
          config={screenshot.config}
          screenshot={screenshot}
          onChange={(value) => onDisplayConfigChange(value)}
        />
      ));
    }
  }, [displayConfigs, screenshotOfDisplays]);

  if (pendingPickerConfig || pendingScreenshotOfDisplays) {
    return (
      <section>
        等待 {JSON.stringify({ pendingPickerConfig, pendingScreenshotOfDisplays })}
      </section>
    );
  }

  return (
    <StyledConfiguratorContainer>
      <CompletedLedStrip
        screenshots={screenshotOfDisplays}
        onDisplayConfigChange={onDisplayConfigChange}
      />
      <StyledDisplayContainer tw="overflow-y-auto">{displays}</StyledDisplayContainer>
      <Fab
        aria-label="reset"
        size="small"
        tw="top-2 right-2 absolute"
        onClick={resetBackToDefaultConfig}
      >
        <FontAwesomeIcon icon={faRotateBack} />
      </Fab>
      <Snackbar open={pendingGetLedColorsByConfig} autoHideDuration={3000}>
        <Alert icon={<FontAwesomeIcon icon={faSpinner} />} sx={{ width: '100%' }}>
          This is a success message!
        </Alert>
      </Snackbar>
    </StyledConfiguratorContainer>
  );
};

export const Configurator = () => {
  return (
    <LedCountProvider>
      <ConfiguratorInner />
    </LedCountProvider>
  );
};
