import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useDispatch } from 'react-redux';
import message from 'components/message';
import { Drawer, Utils } from '@easyv/react-gui';
import styles from './index.less';
import { CmykOutlined, SkinOutlined } from '@easyv/react-icons';
import classNames from 'classnames';
import ScreenFilter from '../ScreenFilter/ScreenFilter';
import ThemePackage from './ThemePackage';
import { updateThemeConfig } from '@lidakai/utils';
import { findComponent, monitorThemeStatus } from 'utils/theme';
import { getTopScreenId } from 'utils/screen';
import { themeComponentBackUp, applyThemeOfScreen, clearThemeComponentBackUp } from 'models/theme';
import { ByIdType } from './index';
import { ThemeType, Status } from 'models/theme.types';
import isObject from 'lodash/isObject';
import { updateComponentsThemeConfig, resetComponentsThemeConfig } from 'models/component';
import { updateScreenStyle } from 'models/screen';

let timer;
let hide;
let controller;
const { updateArrayConfig } = Utils;

export enum State {
  THEME, // 主题
  FILTER // 滤镜
}
const config = [
  {
    name: '主题包',
    id: State.THEME,
    Icon: SkinOutlined
  },
  {
    name: '全局滤镜',
    id: State.FILTER,
    Icon: CmykOutlined
  }
];

const Title = ({ state, onClick }) => {
  return (
    <div className={styles.title}>
      <ul>
        {config.map((d) => (
          <li className={classNames({ [styles.activation]: state === d.id })} key={d.id} onClick={() => onClick(d)}>
            <d.Icon className={styles.icon} />
            <span>{d.name}</span>
          </li>
        ))}
      </ul>
    </div>
  );
};

function ScreenTheme({
  visible,
  onClose,
  setStatus,
  screensById,
  status,
  componentsById,
  themeComponentById,
  themeConfigList = [],
  panelsById
}: {
  visible: boolean;
  onClose: () => any;
  setStatus: (x: Status) => void;
  screensById: ByIdType;
  status: Status;
  themeConfigList: ThemeType[];
  themeComponentById: ByIdType;
  componentsById: ByIdType;
  panelsById: ByIdType;
}) {
  const count = useRef(0); // 标记
  const [state, setState] = useState<State>(0);
  const [componentIds, setComponentIds] = useState<number[]>([]);
  const dispatch = useDispatch();
  const screenId = getTopScreenId();
  const screen = screensById[screenId];

  useEffect(() => {
    if (visible) {
      const _componentIds: number[] = findComponent({
        screensById,
        panelsById,
        screenId
      });
      setComponentIds(_componentIds);
    }
  }, [screenId, panelsById, screensById, visible]);

  useEffect(() => {
    controller = window.AbortController && new AbortController();
    return () => {
      onResetComponentsThemeConfig();
      hide && hide?.();
      timer && clearTimeout(timer);
      controller && controller.abort();
    };
  }, []);

  useEffect(() => {
    if (!visible) {
      // 关闭
      onResetComponentsThemeConfig();
    }
  }, [visible]);

  const configurationUpdate = async (themeConfig) => {
    const components = componentIds
      .map((id) => {
        return componentsById[id];
      })
      .filter((d) => d);

    // 先备份
    if (isObject(themeComponentById) && Array.isArray(components) && !count.current) {
      await dispatch(themeComponentBackUp({ components }));
      count.current += 1;
    }

    // 配置项替换
    const _newComponent = updateThemeConfig({
      components,
      theme: themeConfig
    });

    // 更新redux 数据
    if (Array.isArray(_newComponent) && _newComponent.length) {
      dispatch(updateComponentsThemeConfig(_newComponent)); // redux 更新
    }
    if (themeConfig) {
      dispatch(
        updateScreenStyle({
          id: screenId,
          config: updateArrayConfig(screen.config, [
            {
              path: ['style', 'backgroundColor'],
              value: themeConfig?.bgColor
            }
          ])
        })
      );
    }
  };

  const onChange = async (themeId) => {
    if (!themeId) {
      return;
    }

    const theme = themeConfigList.find((d) => d.id === themeId);
    theme && configurationUpdate(theme.config);
  };

  const onEditeThemeChange = (themeConfig) => {
    // 主题编辑 - > 调试edit screen
    themeConfig && configurationUpdate(themeConfig);
  };

  const onResetComponentsThemeConfig = useCallback(()=>{
    count.current = 0;
    dispatch(resetComponentsThemeConfig());
  },[]);

  const applyTheme = useCallback(
    async (id) => {
      hide = message.loading('主题应用中', 0);
      setStatus(Status.StartTask);
      const result = await applyThemeOfScreen({
        status: Status.StartTask,
        themeId: id,
        screenId
      });
      if (result) {
        timer = monitorThemeStatus(
          screenId,
          (themeStatus) => {
            // 如果任务完成
            if (themeStatus?.status === Status.CancelTask) {
              hide();
              message.success('应用成功');
              count.current = 0;
              setStatus(Status.CancelTask);
              dispatch(clearThemeComponentBackUp());
              onClose?.(); // 关闭
            } else if (!themeStatus) {
              setStatus(Status.CancelTask);
              if (themeStatus === undefined && !/\/create\//i.test(window.location.pathname)) {
                return;
              }
              message.error('应用失败');
            }
          },
          controller && controller.signal
        );
      } else {
        setStatus(Status.CancelTask);
      }
    },
    [screenId]
  );

  return (
    <>
      <Drawer
        className={classNames(styles.drawer)}
        closable={false}
        title={
          <Title
            state={state}
            onClick={(d) => {
              setState(d.id);
            }}
          />
        }
        placement="right"
        visible={visible}
        mask={true}
        width={334}
        onClose={onClose}>
        <div style={{ paddingTop: 13, height: 'calc(100vh - 100px)' }}>
          {status === Status.StartTask && (
            <div className={styles.markLoading}>
              <span>主题应用中...</span>
            </div>
          )}

          <span style={{ display: state === State.FILTER ? 'block' : 'none', height: '100%' }}>
            <ScreenFilter onClose={onClose} />
          </span>
          <span style={{ display: state === State.THEME ? 'block' : 'none', height: '100%' }}>
            <ThemePackage
              visible={visible}
              themeConfigList={themeConfigList}
              onClose={onClose}
              onResetComponentsThemeConfig={onResetComponentsThemeConfig}
              onEditeThemeChange={onEditeThemeChange}
              onOk={applyTheme}
              onChange={onChange}
            />
          </span>
        </div>
      </Drawer>
    </>
  );
}

export default ScreenTheme;
