import React, { useEffect, useMemo, useRef, useState } from "react";

import WeekToggler from "./datePicker";
import dayjs from "dayjs";
import './calendar.scss';

import { dataMapping } from "../../utils/tpl-builtin";
import { IScopedContext } from "../../Scoped";
import { createObject } from "../../utils/helper";
import { Spin } from "antd";

interface EventsFromApi {
  START_TIME: string;
  END_TIME: string;
  content: string;
  NAME?: string;
}

const CalendarComp = (props: any) => {
  const { render, env, api, alert, receiveData, isMobile, primaryField, schedules, lazyLoad, itemAction, context, calendarType, noEdit } = props;
  const initTypeMap = {
    'schedule': isMobile ? 'timeGridDay' : 'timeGridWeek',
    // 'meeting': isMobile ? 'timeGridDay' : 'timeGridWeek',
    'calendar': 'dayGridMonth'
  }
  const currentViewType = useRef(initTypeMap[calendarType]);
  // const [allEventsRef.current, setAllEvents] = useState<EventsFromApi>([]);
  const [initDate, setInitDate] = useState<string>();

  const allEventsRef = useRef([]);
  const [allEvents, setAllEvents] = useState([]);
  const [fetchLoading, setFetchLoading] = useState(false);
  const reqDateConfig = useRef({});
  const weekTogglerRef = useRef({});
  const scheduleMap = new Map();
  const [scheduleKeyMap, setScheduleKeyMap] = useState({});
  const eventBgColorMap = {
    warning: { backgroundColor: '#FE9201' },
    'background-warning': { backgroundColor: '#FEF3E6', color: '#FE9201' },
    success: { backgroundColor: '#15B37B' },
    'background-success': { backgroundColor: '#E8F8F2', color: '#15B37B' },
    primary: { backgroundColor: '#3574EE' },
    'background-primary': { backgroundColor: '#E9F6FE', color: '#3574EE' },
    danger: { backgroundColor: '#F5222D' },
    'background-danger': { backgroundColor: '#FAEDEE', color: '#F5222D' },
  }

  useEffect(() => {
    handleGenNewMap();
    handleInit();
  }, []);
  useEffect(() => {
    if (Object.keys(receiveData).length) {
      const date = dayjs().format('YYYY-MM-DD');
      weekTogglerRef.current?.handleYearMonthChange?.('', date, true);
      handleInit(date);
    }
  }, [receiveData]);
  const currentMonth = useRef(dayjs(initDate).get('M'));
  const getMapKey = (key: string) => {
    return schedules[key] ? schedules[key].match(/\$\{([^}]+)\}/)?.[1] : key;
  }
  const handleGenNewMap = async () => {
    schedules['id'] = '${' + primaryField + '}';
    schedules['start'] = schedules['startTime'];
    schedules['end'] = schedules['endTime'];
    const keys = Object.keys(schedules);

    keys.forEach((key) => {
      scheduleMap.set(key, getMapKey(key));
      scheduleMap.set(getMapKey(key), key);
      if (key === 'content') {
        scheduleMap.set('title', getMapKey(key));
        scheduleMap.set(getMapKey(key), 'title');
      }
    });
    const keysMap = Object.fromEntries(scheduleMap.entries());
    setScheduleKeyMap(() => keysMap);
  };
  /** 获取某个时间段的事件 */
  const handleInitEvents = async (dates) => {
    const startTimeKey = scheduleMap.get('startTime') || scheduleKeyMap['startTime'];
    const endTimeKey = scheduleMap.get('endTime') || scheduleKeyMap['endTime'];
    const { advancedFilter: advancedFilterConfig } = api?.data ?? {};
    const startTime = dayjs(dates[startTimeKey]).format('YYYY-MM-DD');
    const endTime = dayjs(dates[endTimeKey]).format('YYYY-MM-DD');

    if (!lazyLoad && allEvents.length) {
      return allEvents;
    } else {
      let params = {};
      // lazyLoad: 是否懒加载 是：只请求区间信息，否：请求所有数据 
      // advancedFilterConfig： 是否有高级查询  是：走高级查询 否：按开始时间结束时间
      if (lazyLoad) {
        if (advancedFilterConfig) {
          const advancedFilter = [];
          // 如果起止时间的key相同，则用区间
          const baseConfig = {
            condition: 1,
            not: false,
            dateLine: true,
            caseSensitive: 1,
          };

          if (startTimeKey === endTimeKey) {
            advancedFilter.push({
              ...baseConfig,
              field: startTimeKey,
              op: 7,
              values: dates['timeRange']?.join(','),
            })
          } else {
            [0, 1].forEach((item) => {
              advancedFilter.push({
                ...baseConfig,
                // 4: 从  6： 到
                op: !item ? 4 : 6,
                field: !item ? startTimeKey : endTimeKey,
                values: !item ? startTime : endTime
              })
            })
          }
          params = { advancedFilter }
        } else {
          const normalLazyParam = {};
          if (startTimeKey === endTimeKey) {
            normalLazyParam[startTimeKey] = dates['timeRange']?.join(',');
          } else {
            normalLazyParam[startTimeKey] = startTime;
            normalLazyParam[endTimeKey] = endTime;
          }
          params = normalLazyParam;
        }
      }
      try {
        const res = await env.fetcher(api, { ...params, ...receiveData });
        if (res.ok) {
          const transEvents = transEventFitCalendar(res.data ?? []);
          return transEvents;
        }
      } finally {
        setFetchLoading(false);
      }
    }
    return []
  }

  // 获取日历时间区间, 从当月周一的日期往后数41天，共42天数据, 不传则按当月计算
  const handleGenInitDate = (initDate?: string) => {
    const firstDayOfWeek = dayjs(initDate).startOf('M').startOf('w').format('YYYY-MM-DD HH:mm:ss');
    const endDate = dayjs(firstDayOfWeek).add(41, 'day').endOf('d').format('YYYY-MM-DD HH:mm:ss');
    const dates = {};
    const startKey = getMapKey('startTime');
    const endKey = getMapKey('endTime')
    dates['timeRange'] = [firstDayOfWeek, endDate];
    dates[startKey] = firstDayOfWeek;
    dates[endKey] = endDate;
    return dates;
  }
  // 获取所有事件
  const handleGetAllEvents = async (initDate?) => {
    const dates = handleGenInitDate(initDate);
    const events = await handleInitEvents(dates);
    reqDateConfig.current = dates;
    if (!initDate) {
      setInitDate(dayjs().format('YYYY-MM-DD'));
    } else {
      // debug
      setInitDate(dayjs(initDate).format('YYYY-MM-DD'))
    }
    setAllEvents(() => events);
    allEventsRef.current = events;
  }

  // 判断是否可以手动初始化
  const handleJudgeShouldInit = (initDate) => {
    if (initDate) {
      const [startTime, endTime] = Object.values(reqDateConfig.current) ?? [];
      if (startTime && endTime) {
        const dateMonth = dayjs(initDate).get('M');

        if (dateMonth !== currentMonth.current) {
          // handleInit(dayjs(initDate).format('YYYY-MM-DD HH:mm:ss'));
          currentMonth.current = dayjs(initDate).get('M');
          return true
        }
      }

    }
    return false;
  }

  /** 初始化  传入日期，将获取当月第一周的周一往后41天的数据 */
  const handleInit = async (initDate?) => {
    setFetchLoading(true);
    await handleGetAllEvents(initDate);
  }

  const transEventFitCalendar = (events: EventsFromApi[]): EventsFromApi[] => {
    const eventsForCalendar = events.map((item) => {
      const data = dataMapping(schedules, item);
      return { ...item, ...data }
    });
    return eventsForCalendar;
  }

  const handleClickItemAction = (date) => {
    const { target } = itemAction
    // const matchEvents = allEvents.filter((item) => dayjs(item.start).format('YYYY-MM-DD') === dayjs(date).format('YYYY-MM-DD')).filter(Boolean);

    const params = {};
    const startTimeKey = scheduleKeyMap['startTime'];
    const endTimeKey = scheduleKeyMap['endTime'];
    const startTime = dayjs(date).startOf('d').format('YYYY-MM-DD HH:mm:ss');
    const endTime = dayjs(date).endOf('d').format('YYYY-MM-DD HH:mm:ss');
    params[startTimeKey] = startTime;
    params[endTimeKey] = endTime;
    reloadTarget(target, createObject(props.data, params));
  }
  const reloadTarget = (target: string, data: any) => {
    const scoped = context as IScopedContext;
    scoped.reload(target, data);
  }

  const handleDateToggle = (date, isInit) => {
    if (date) {
      const formattedDate = dayjs(date).format('YYYY-MM-DD');
      const shouldInit = handleJudgeShouldInit(formattedDate);

      if (shouldInit) {
        setTimeout(() => {
          requestAnimationFrame(() => {
            handleInit(formattedDate);
          })
        }, 800);
      } else {
        setInitDate(formattedDate);
      }
      // calendarInsRef.current?.gotoDate(date);
      (isInit && itemAction) && handleClickItemAction(date);
    }
  };


  // 当日历手动切换，calendar组件做出响应
  const handleToggleCalendar = (
    dateType: string,
    toggleType: string,
    date: dayjs.Dayjs
  ) => {
    const targetDate = dayjs(date).valueOf();

    setTimeout(() => {
      requestAnimationFrame(() => {
        currentMonth.current = dayjs(targetDate).get('M');
        handleJudgeShouldInit(targetDate) && handleInit(targetDate);
      });
    }, 500);
  };

  const handleTogglePanel = (val, mode: string) => {
    const initDate = dayjs(val).format('YYYY-MM-DD HH:mm:ss');
    const shouldUpdate = handleJudgeShouldInit(initDate);

    if (shouldUpdate) {
      handleInit(initDate);
    }

  };
  // 移动端获取当天的数据
  const handleGetAttendance = useMemo(() => {
    const parsedDay = dayjs(initDate).format('YYYY-MM-DD').valueOf();
    const matchEvents = allEvents.filter((item) => {
      let isMatch = false;
      const startTime = dayjs(item.startTime?.replaceAll('.', '-')).format('YYYY-MM-DD').valueOf();
      const endTime = dayjs(item.endTime?.replaceAll('.', '-')).format('YYYY-MM-DD').valueOf();

      isMatch = parsedDay >= startTime && parsedDay <= endTime;
      return isMatch ? item : undefined
    }).filter(Boolean);

    if (matchEvents?.length) {
      const renderDom = matchEvents.map((item) => {
        const { title, content } = item;
        return (
          <div className="info-box">
            <div className="title">{render('tpl', { type: 'tpl', tpl: title })}</div>
            {render('tpl', { type: 'tpl', tpl: content })}
          </div>
        )

      })
      return (<div className="attendance-box">{renderDom}</div>);
    }
    return null;
  }, [allEvents, initDate]);


  const weekViewMap = {
    'schedule': true,
    'calendar': false,
    // 'meeting': true,
    // 'attendance': false
  }
  return (
    <div className={`calendar-container ${calendarType} ${isMobile ? 'mobile' : ''}`}>
      <Spin spinning={fetchLoading}>

        <div className={`week-toggler-box ${calendarType}`}>
          {/* {weekTogglerRender} */}
          <WeekToggler
            ref={weekTogglerRef}
            events={allEvents}
            initDate={initDate}
            onDateSelected={handleDateToggle}
            onToggleCalendar={handleToggleCalendar}
            onPanelToggle={handleTogglePanel}
            viewType={currentViewType.current}
            isWeekView={weekViewMap[calendarType]}
            isMobile={isMobile}
            alertText={alert}
            render={render}
          />
        </div>
        {/* 考勤记录渲染 */}
        { calendarType === 'calendar' && !itemAction ? <>{handleGetAttendance}</> : null }
      </Spin>
    </div>
  );
};



export default CalendarComp;
