import type { Reducer, Effect, CurrentUser } from 'umi';
import type { NoticeIconData } from '@/components/NoticeIcon';
import { changeNoticesState, getUserMenu, queryNotices, setMessageState } from '@/services/user';
import type { ConnectState } from './connect.d';
import type { MenuDataItem } from '@ant-design/pro-layout';
import { menuFormatter } from '@/utils/menuformatter';
import session from '@/utils/session';
import globalState from '@/globalState';
import { wrapTreeNode } from "@/utils/format";


export type NoticeItem = {
	id: string;
	type: string;
	status: string;
} & NoticeIconData;

export type tabsRoute = {
	title: string;
	path: string;
	key: string;
	children: any;
}

export type GlobalModelState = {
	collapsed: boolean;
	notices: NoticeItem[];
	tabsRoutes: tabsRoute[];
	menuData: MenuDataItem[];
	moduleMap: MenuDataItem[];
};

export type GlobalModelType = {
	namespace: 'global';
	state: GlobalModelState;
	effects: {
		fetchNotices: Effect;
		clearNotices: Effect;
		changeNoticeReadState: Effect;
		changeTabsRoutes: Effect;
		getMenuData: Effect;
	};
	reducers: {
		changeLayoutCollapsed: Reducer<GlobalModelState>;
		saveNotices: Reducer<GlobalModelState>;
		saveClearedNotices: Reducer<GlobalModelState>;
		saveTabsRoutes: Reducer<GlobalModelState>;
		saveMenuData: Reducer<GlobalModelState>;
		saveMenuModuleMap: Reducer<GlobalModelState>;
	};
};

const GlobalModel: GlobalModelType = {
	namespace: 'global',

	state: {
		collapsed: false,
		notices: [],
		tabsRoutes: [],
		menuData: [],
		moduleMap: []
	},

	effects: {
		*getMenuData({ payload, callback }, { put, call }) {
			const response = yield call(getUserMenu, payload);

			const menuData = menuFormatter(response);
			// const menuData = wrapTreeNode(response);
			globalState.set('menuData', menuData);

			yield put({
				type: 'saveMenuData',
				payload: menuData,
			});

			yield put({
				type: 'saveMenuModuleMap',
				payload: menuFormatter(response),
			});
			if (callback && typeof callback === 'function') {
				callback(response)
			}
		},
		*fetchNotices(_, { call, put, select }) {

			const user: CurrentUser = yield select(
				(state: ConnectState) => state.user.currentUser
			);
			const data = yield call(queryNotices, { RECSTAFF_ID: user?.ID });
			globalState.set('notices', data);
			yield put({
				type: 'saveNotices',
				payload: data,
			});
			const unreadCount: number = yield select(
				(state: ConnectState) => state.global.notices.filter((item) => item.MESSAGE_STATE === 1).length,
			);
			yield put({
				type: 'user/changeNotifyCount',
				payload: {
					totalCount: data.length,
					unreadCount,
				},
			});
		},
		*clearNotices({ payload }, { put, select, call }) {

			const user: CurrentUser = yield select(
				(state: ConnectState) => state.user.currentUser
			);
			const notices: NoticeItem[] = yield select(
				(state: ConnectState) => state.global.notices
			);
			const clearNoticeIds = notices.reduce((p: any[], c) => {
				if (c.MESSAGE_TYPE === (payload as number)) {
					return [...p, c.MESSAGE_ID]
				}

				return p
			}, [])
			const success = yield call(setMessageState, {
				messageIds: clearNoticeIds.toString(),
				recStaffId: user?.ID,
				messageState: 2
			}
			);
			if (success) {
				yield put({
					type: 'saveClearedNotices',
					payload,
				});

				const count: number = yield select((state: ConnectState) => state.global.notices.length);
				const unreadCount: number = yield select(
					(state: ConnectState) => state.global.notices.filter((item) => item.MESSAGE_STATE === 1).length,
				);
				yield put({
					type: 'user/changeNotifyCount',
					payload: {
						totalCount: count,
						unreadCount,
					},
				});
			}
		},
		* changeNoticeReadState({ payload }, { call, put, select }) {
			const notices: NoticeItem[] = yield select((state: ConnectState) =>
				state.global.notices.map((item) => {
					const notice = { ...item };
					if (notice.MESSAGE_ID === payload) {
						notice.MESSAGE_STATE = 2;
					}
					return notice;
				}),
			);
			const success = yield call(changeNoticesState, notices.find(n => n.MESSAGE_ID === payload));
			if (success) {
				yield put({
					type: 'saveNotices',
					payload: notices,
				});

				yield put({
					type: 'user/changeNotifyCount',
					payload: {
						totalCount: notices.length,
						unreadCount: notices.filter((item) => item.MESSAGE_STATE === 1).length,
					},
				});
			}
		},
		* changeTabsRoutes({ payload, callback }, { put, select }) { // 缓存路由栈

			const tabsRoutes: tabsRoute[] = yield select((state: ConnectState) => {
				const { data } = payload

				if (payload.action === 'add') {
					const index = state.global.tabsRoutes.findIndex(n => n.path === data.path)

					if (index === -1) { // 没缓存 则添加
						return [...state.global.tabsRoutes, { ...data, index: state.global.tabsRoutes.length }]
					}
					// 否则不操作
					return [...state.global.tabsRoutes]
				}
				if (payload.action === 'removeAll') {
					return []
				}

				if (callback && typeof callback === 'function') {
					callback.call()
				}
				// 移除单个/多个路由
				return state.global.tabsRoutes.filter(n => !data.includes(n.path))
			});

			yield put({
				type: 'saveTabsRoutes',
				payload: tabsRoutes,
			});


		}
	},

	reducers: {
		changeLayoutCollapsed(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {
			return {
				...state,
				collapsed: payload,
			};
		},
		saveNotices(state, { payload }): GlobalModelState {
			return {
				collapsed: false,
				...state,
				notices: payload,
				tabsRoutes: state?.tabsRoutes || [],
				menuData: state?.menuData || [],
				moduleMap: state?.moduleMap || []
			};
		},
		saveClearedNotices(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {
			const type = payload as number
			return {
				...state,
				collapsed: false,
				notices: state.notices.filter((item): boolean => item.MESSAGE_TYPE !== type),
			};
		},
		saveTabsRoutes(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {
			return {
				...state,
				tabsRoutes: payload
			}
		},
		saveMenuData(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState {

			return {
				...state,
				menuData: payload,
			}
		},
		saveMenuModuleMap(state = { notices: [], collapsed: true, tabsRoutes: [], menuData: [], moduleMap: [] }, { payload }): GlobalModelState { // 生成模块

			const reduceMenu = (data: any) => {

				return data.reduce((p: [], current: Record<string, any>) => {

					if (current.children) {
						const d = reduceMenu(current.children)

						return [...p, ...d]
					}

					return [...p, current]
				}, [])
			}

			const moduleMap = reduceMenu(payload)

			session.set('menu', moduleMap)
			return {
				...state,
				moduleMap,
			}
		}
	},
};

export default GlobalModel;
