import React, { useState, useCallback, useEffect, useMemo } from 'react';
import { connect } from 'react-redux';
import QuestionCircleOutlined from '@ant-design/icons/QuestionCircleOutlined';
import { updateEvents } from 'models/component';
import { generateId } from 'utils/utils';
import ConditionEdit from './ConditionEdit';
import EventConfig from './EventConfig';
import { CollapseTabs, Tooltip } from '@easyv/react-gui';
import { defaultAction } from './EventConfig';

const { TabPane } = CollapseTabs;

const defaultEvent = {
  trigger: 'dataChange',
  name: '事件',
  conditionType: 'all',
  conditions: [],
  reverse: true,
  actions: []
};

const Header = () => (
  <>
    <span style={{ flex: 1 }}>
      自定义事件{' '}
      <Tooltip title="自定义事件为「交互事件」的增强模块，支持通过数据驱动组件状态、或变更组件样式配置，也可自定义编辑复杂的条件逻辑；">
        <QuestionCircleOutlined className="whiteHover" />
      </Tooltip>
    </span>
  </>
);

export interface CustomEventProps {
  staticConfig: {
    data: any;
    fields: any;
  };
  events: any[];
  actionId: string;
  eventId: string;
  triggers: {
    name: string;
    value: string;
    type?: string;
    fields?: {
      name: string;
      type: string;
      desc: string;
    }[];
    data?: any;
  }[];
  onComponentChange: (param: any) => void;
  dataUpdateEvents?: (x: any) => void;
}

function CustomEvent({
  staticConfig,
  events: _events,
  triggers = [],
  onComponentChange,
  dataUpdateEvents,
  actionId,
  eventId
}: CustomEventProps) {
  const onChange = dataUpdateEvents || onComponentChange;

  const [conditionEditVisible, setConditionEditVisible] = useState(false);
  const [activeKey, setActiveKey] = useState<string | number>();
  const [eventIndex, setEventIndex] = useState<number>(-1);
  const [conditionId, setConditionId] = useState<number>();

  const events = useMemo(() => {
    return _events.filter((d) => d && d.id && d.name);
  }, [_events]);

  useEffect(() => {
    if (eventId && Array.isArray(events)) {
      const value = events.find((d) => d.id === eventId);
      value && setActiveKey(value.id);
    }
  }, [eventId, events]);

  const handleEventAdd = async (key) => {
    const newKey = `event_${generateId()}`;
    let value;

    // 如果当前有事件，则以当前事件来复制，没有的话则以默认值
    if (events.length) {
      const event = events.find((d) => d.id === key);
      value = { ...event, id: newKey };
    } else {
      value = { ...defaultEvent, actions: [{ ...defaultAction, id: `action_${generateId()}` }], id: newKey };
    }

    await onChange({ paths: [], value, key: events.length });
    return newKey;
  };

  const handleEventDelete = async (key) => {
    const keyIndex = events.findIndex((d) => d.id === key);
    const newKey = keyIndex > 0 ? events[keyIndex - 1].id : events[keyIndex + 1] ? events[keyIndex + 1].id : '';
    await onChange({ paths: [], key: keyIndex });
    return newKey;
  };

  const handleEventSort = ({ oldIndex, newIndex }) => {
    const newEvents = events.concat();
    const target = newEvents.splice(oldIndex, 1);
    newEvents.splice(newIndex, 0, target[0]);
    onChange({ paths: [], value: newEvents });
  };

  const handleConditionEditClose = useCallback(() => {
    setConditionEditVisible(false);
    setEventIndex(-1);
  }, []);

  const handleConditionEditShow = (eventIndex, conditionId) => {
    setEventIndex(eventIndex);
    setConditionId(conditionId);
    setConditionEditVisible(true);
  };

  const currentEvent = typeof eventIndex === 'number' && eventIndex !== -1 ? events[eventIndex] : {};

  const handleEventChange = async (index, updated) => {
    updated = Array.isArray(updated) ? updated : [updated];

    await onChange(updated.map((d) => ({ ...d, paths: [index].concat(d.paths) })));
  };

  const tooltipData = getTooltipData(currentEvent.trigger, triggers, staticConfig);

  return (
    <>
      <CollapseTabs
        header={<Header />}
        activeKey={activeKey}
        collapsed={!activeKey}
        onAdd={handleEventAdd}
        onDelete={handleEventDelete}
        onSort={handleEventSort}>
        {events.map((d, i) => {
          const currentTooltipData = getTooltipData(d.trigger, triggers, staticConfig);
          return (
            <TabPane tab={`${d.name}${i + 1}`} key={d.id}>
              <EventConfig
                tooltipData={currentTooltipData}
                value={d}
                actionId={actionId}
                triggers={triggers}
                onChange={(updated) => handleEventChange(i, updated)}
                onConditionEditShow={(conditionId) => handleConditionEditShow(i, conditionId)}
              />
            </TabPane>
          );
        })}
      </CollapseTabs>

      <ConditionEdit
        tooltipData={tooltipData}
        eventIndex={eventIndex}
        conditionId={conditionId}
        visible={conditionEditVisible}
        type={currentEvent.conditionType}
        value={currentEvent.conditions}
        reverse={currentEvent.reverse}
        onClose={handleConditionEditClose}
        onChange={onChange}
      />
    </>
  );
}

function getTooltipData(trigger, triggers, staticConfig) {
  if (trigger) {
    if (trigger === 'dataChange') {
      return (
        staticConfig.data?.length && {
          type: 'array',
          data: staticConfig.data,
          fields: staticConfig.fields?.map((d) => ({
            name: d.name,
            type: staticConfig.data[0][d.name] ? typeof staticConfig.data[0][d.name] : 'string',
            desc: d.desc
          }))
        }
      );
    } else {
      const current = triggers.find((d) => d.value === trigger);

      return (
        current?.type && {
          type: current.type,
          data: current.data,
          fields: current.fields
        }
      );
    }
  }
}

const mapDispatchToProps = {
  onComponentChange: updateEvents
};

export default connect(null, mapDispatchToProps)(CustomEvent);
