import {saveAs} from 'file-saver';
import {
  types,
  getParent,
  flow,
  getEnv,
  getRoot,
  isAlive,
  Instance
} from 'mobx-state-tree';
import {IRendererStore} from './index';
import {ServiceStore} from './service';
import {
  extendObject,
  createObject,
  isObjectShallowModified,
  sortArray,
  isEmpty,
  qsstringify
} from '../utils/helper';
import {Api, Payload, fetchOptions, Action, ApiObject} from '../types';
import pick from 'lodash/pick';
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
import {normalizeApiResponseData} from '../utils/api';
import { CRUD_CONST } from '../constants/api'
import { LayoutModeEnum } from '../constants/table-enum'


class ServerError extends Error {
  type = 'ServerError';
}



export const CRUDStore = ServiceStore.named('CRUDStore')
  .props({
    pristineQuery: types.optional(types.frozen(), {}),// 记录当前已经请求过的query
    query: types.optional(types.frozen(), {}),// 请求参数
    prevPage: 1,
    page: 1,
    perPage: 10,
    total: 0,
    mode: 'normal',
    hasNext: false,
    selectedAction: types.frozen(),
    columns: types.frozen(),
    items: types.optional(types.array(types.frozen()), []),
    selectedItems: types.optional(types.array(types.frozen()), []),
    unSelectedItems: types.optional(types.array(types.frozen()), []),
    filterTogggable: false,// 筛选按钮开关是否显示
    filterVisible: true,// 筛选器是否显示
    hasInnerModalOpen: false,
    adFilterToggable: false,// 高级筛选是否显示
    curAdFilterId: types.optional(types.union(types.null, types.string), null),
    curCardId: types.optional(types.union(types.null, types.string), null),// 选中的card_id
    advancedFilterOriginal: types.optional(types.array(types.frozen()), []),// 和接口同步的数据
    advancedFilter: types.optional(types.array(types.frozen()), []),// 用于显示卡片 可能包含未保存的卡片
    dynamicFieldKey: types.optional(types.union(types.null, types.string), null),
    dynamicFieldValue: types.optional(types.union(types.null, types.string, types.number), null),

    layoutMode: LayoutModeEnum.table,
  })
  .views(self => ({
    get lastPage() {
      return Math.max(
        Math.ceil(self.total / (self.perPage < 1 ? 10 : self.perPage)),
        1
      );
    },

    get curPageSize() {
      if(self.page < this.lastPage){
        return self.perPage
      }else{
        return self.total % self.perPage
      }
    },

    get filterData() {
      return createObject(self.data, {
        ...self.query
      });
    },

    get mergedData() {
      return extendObject(self.data, {
        ...self.query,
        ...self.data,
        selectedItems: self.selectedItems,
        unSelectedItems: self.unSelectedItems
      });
    },

    get hasModalOpened() {
      return self.dialogOpen || self.drawerOpen || self.hasInnerModalOpen;
    },

    get selectedItemsAsArray() {
      return self.selectedItems.concat();
    },

    get curAdvancedFilterCard(){
      return self.advancedFilter.filter(v=> v.CARD_ID === self.curCardId)?.[0] || {}
    },

    get layoutModeText(){
      return self.layoutMode === LayoutModeEnum.table? '表格': (
        self.layoutMode === LayoutModeEnum.wide? '宽详情': '窄详情'
      )
    },

    fetchCtxOf(
      data: any,
      options: {
        pageField?: string;
        perPageField?: string;
      }
    ) {
      return createObject(data, {
        ...self.query,
        [options.pageField || CRUD_CONST.pageField]: self.page,
        [options.perPageField || CRUD_CONST.perPageField]: self.perPage,
        ...data
      });
    }
  }))
  .actions(self => {
    let fetchCancel: Function | null = null;

    function setPristineQuery() {
      self.pristineQuery = self.query;
    }

    function updateQuery(
      values: object,
      updater?: Function,
      pageField?: string,
      perPageField?: string,
      replace: boolean = false
    ) {
      pageField = pageField || CRUD_CONST.pageField;
      perPageField = perPageField || CRUD_CONST.perPageField;

      const originQuery = self.query;
      self.query = replace
        ? {
            ...values
          }
        : {
            ...self.query,
            ...values
          };

      if (self.query[pageField]) {
        self.page = parseInt(self.query[pageField], 10);
      }

      if (self.query[perPageField]) {
        self.perPage = parseInt(self.query[perPageField], 10);
      }

      updater &&
        isObjectShallowModified(originQuery, self.query, false) &&
        setTimeout(updater.bind(null, `?${qsstringify(self.query)}`), 4);
    }

    const fetchPreData: (
      api: Api,
      data?: object,
      options?: fetchOptions & {
        forceReload?: boolean;
        loadDataOnce?: boolean; // 配置数据是否一次性加载，如果是这样，由前端来完成分页，排序等功能。
        loadDataOnceFetchOnFilter?: boolean; // 在开启loadDataOnce时，filter时是否去重新请求api
        source?: string; // 支持自定义属于映射，默认不配置，读取 rows 或者 items
        loadDataMode?: boolean;
        syncResponse2Query?: boolean;
      }
    ) => Promise<any> = flow(function* getPreData(
      api: Api,
      data: object,
      options: fetchOptions = {}
    ){
      try {

        const ctx: any = {}

        const json: Payload = yield getEnv(self).fetcher(api, ctx, {
          ...options,
        });

        if (!json.ok) {
          self.updateMessage(
            json.msg ?? options.errorMessage ?? self.__('CRUD.fetchFailed'),
            true
          );
          getEnv(self).notify(
            'error',
            json.msg,
            json.msgTimeout !== undefined
              ? {
                  closeButton: true,
                  timeout: json.msgTimeout
                }
              : undefined
          );
        } else {
          if (!json.data) {
            throw new Error(self.__('CRUD.invalidData'));
          }

          let filterData: any = Array.isArray(json.data)? json.data: [];
          // 转成前端需要的格式
          filterData = filterData.map((card: any) => {
            let CARD_CONTENT = card.CARD_CONTENT || '[]';
            try{
              CARD_CONTENT = JSON.parse(CARD_CONTENT)
            }catch(e){
              CARD_CONTENT = []
            }

            return {
              ...card,
              CARD_CONTENT
            }
          })
          
          // 将后端数据存一份
          self.advancedFilterOriginal = filterData
          
          // 设置默认卡片id
          let defaultCard = filterData.filter((v: any)=> v.CARD_DEFAULT === 'Y')
          self.curAdFilterId = defaultCard?.[0]?.['CARD_ID'] || null;


          // 设置card tabs
          // 如果没有 则创建一个 未保存的
          let showCards = filterData.filter((v: any)=> v.CARD_DISPLAY === 'Y')

          if(!showCards.length){
            let CARD_ID = "高级筛选1";
            self.curCardId = CARD_ID;
            self.advancedFilter = [{
              CARD_ID,
              CARD_NAME: CARD_ID,
              CARD_CONTENT: "",
              CARD_DEFAULT: "N",
              CARD_DISPLAY: "Y",
              CARD_TYPE: "P",
              isSave: false,
            }] as any
          }else{
            self.curCardId = defaultCard?.[0]?.['CARD_ID'] || showCards?.[0]?.['CARD_ID'] || null;
            self.advancedFilter = showCards.map((v: any)=> ({
              ...v,
              isSave: true,
            }))
          }

          self.updateMessage(json.msg ?? options.successMessage);
          // 配置了获取成功提示后提示，默认是空不会提示。
          options &&
            options.successMessage &&
            getEnv(self).notify('success', self.msg);
        }
        return json;
      } catch (e) {
        const env = getEnv(self) as IRendererStore;

        if (!isAlive(self) || self.disposed) {
          return;
        }

        self.markFetching(false);

        if (env.isCancel(e)) {
          return;
        }

        console.error(e.stack);
        env.notify('error', e.message);
        return;
      }
    })

    const fetchInitData: (
      api: Api,
      data?: object,
      options?: fetchOptions & {
        forceReload?: boolean;
        loadDataOnce?: boolean; // 配置数据是否一次性加载，如果是这样，由前端来完成分页，排序等功能。
        loadDataOnceFetchOnFilter?: boolean; // 在开启loadDataOnce时，filter时是否去重新请求api
        source?: string; // 支持自定义属于映射，默认不配置，读取 rows 或者 items
        loadDataMode?: boolean;
        syncResponse2Query?: boolean;
      }
    ) => Promise<any> = flow(function* getInitData(
      api: Api,
      data: object,
      options: fetchOptions & {
        forceReload?: boolean;
        loadDataOnce?: boolean; // 配置数据是否一次性加载，如果是这样，由前端来完成分页，排序等功能。
        loadDataOnceFetchOnFilter?: boolean; // 在开启loadDataOnce时，filter时是否去重新请求api
        source?: string; // 支持自定义属于映射，默认不配置，读取 rows 或者 items
        loadDataMode?: boolean;
        syncResponse2Query?: boolean;
      } = {}
    ) {
      try {
        if (!options.forceReload && options.loadDataOnce && self.total) {
          let items = options.source
            ? resolveVariableAndFilter(
                options.source,
                createObject(self.mergedData, {
                  items: self.data.itemsRaw,
                  rows: self.data.itemsRaw
                }),
                '| raw'
              )
            : self.items.concat();

          if (self.query.orderBy) {
            const dir = /desc/i.test(self.query.orderDir) ? -1 : 1;
            items = sortArray(items, self.query.orderBy, dir);
          }

          const data = {
            ...self.data,
            total: items.length,
            items: items.slice(
              (self.page - 1) * self.perPage,
              self.page * self.perPage
            )
          };
          self.total = parseInt(data.total ?? data.count, 10) || 0;
          self.reInitData(data);
          return;
        }

        if (fetchCancel) {
          fetchCancel();
          fetchCancel = null;
          self.fetching = false;
        }

        options.silent || self.markFetching(true);
        const ctx: any = createObject(self.data, {
          ...self.query,
          ...data,
          [options.pageField || CRUD_CONST.pageField]: self.page,
          [options.perPageField || CRUD_CONST.perPageField]: self.perPage
        });

        // 一次性加载不要发送 perPage 属性
        if (options.loadDataOnce) {
          delete ctx[options.perPageField || CRUD_CONST.perPageField];
        }

        const json: Payload = yield getEnv(self).fetcher(api, ctx, {
          ...options,
          cancelExecutor: (executor: Function) => (fetchCancel = executor)
        });
        fetchCancel = null;

        if (!json.ok) {
          self.updateMessage(
            json.msg ?? options.errorMessage ?? self.__('CRUD.fetchFailed'),
            true
          );
          getEnv(self).notify(
            'error',
            json.msg,
            json.msgTimeout !== undefined
              ? {
                  closeButton: true,
                  timeout: json.msgTimeout
                }
              : undefined
          );
        } else {
          if (!json.data) {
            throw new Error(self.__('CRUD.invalidData'));
          }

          self.updatedAt = Date.now();
          let result = normalizeApiResponseData(json.data);

          const {
            total,
            count,// 总条数
            totalElements,// 总条数
            page,
            hasNext,
            items: oItems,// 表格数据
            rows: oRows,// 表格数据
            content: oContent,// 表格数据
            columns,
            ...rest
          } = result;

          let items: Array<any>;
          if (options.source) {
            items = resolveVariableAndFilter(
              options.source,
              createObject(self.filterData, result),
              '| raw'
            );
          } else {
            items = oContent || oItems || oRows;
          }

          if (!Array.isArray(items)) {
            throw new Error(self.__('CRUD.invalidArray'));
          } else {
            // 确保成员是对象。
            items.map((item: any) =>
              typeof item === 'string' ? {text: item} : item
            );
          }

          // 点击加载更多数据
          let rowsData = [];
          if (options.loadDataMode && Array.isArray(self.data.items)) {
            rowsData = self.data.items.concat(items);
          } else {
            // 第一次的时候就是直接加载请求的数据
            rowsData = items;
          }

          const data = {
            ...((api as ApiObject).replaceData ? {} : self.pristine),
            items: rowsData,
            count: totalElements || count,
            total: total,
            ...rest
          };

          if (options.loadDataOnce) {
            // 记录原始集合，后续可能基于原始数据做排序查找。
            data.itemsRaw = oContent ||  oItems || oRows;

            if (self.query.orderBy) {
              const dir = /desc/i.test(self.query.orderDir) ? -1 : 1;
              rowsData = sortArray(rowsData, self.query.orderBy, dir);
            }
            data.items = rowsData.slice(
              (self.page - 1) * self.perPage,
              self.page * self.perPage
            );
            data.count = data.total = rowsData.length;
          }

          if (Array.isArray(columns)) {
            self.columns = columns.concat();
          } else {
            self.columns = undefined;
          }

          self.items.replace(rowsData);
          console.log(`⭐️ ~ 新的数据`)
          self.reInitData(data, !!(api as ApiObject).replaceData);
          options.syncResponse2Query !== false &&
            updateQuery(
              pick(rest, Object.keys(self.query)),
              undefined,
              options.pageField || CRUD_CONST.pageField,
              options.perPageField || CRUD_CONST.perPageField
            );

          self.total = parseInt(data.total ?? data.count, 10) || 0;
          typeof page !== 'undefined' && (self.page = parseInt(page, 10));

          // 分页情况不清楚，只能知道有没有下一页。
          if (typeof hasNext !== 'undefined') {
            self.mode = 'simple';
            self.total = 0;
            self.hasNext = !!hasNext;
          }

          self.updateMessage(json.msg ?? options.successMessage);

          // 配置了获取成功提示后提示，默认是空不会提示。
          options &&
            options.successMessage &&
            getEnv(self).notify('success', self.msg);
        }

        self.markFetching(false);
        return json;
      } catch (e) {
        const env = getEnv(self) as IRendererStore;

        if (!isAlive(self) || self.disposed) {
          return;
        }

        self.markFetching(false);

        if (env.isCancel(e)) {
          return;
        }

        console.error(e.stack);
        env.notify('error', e.message);
        return;
      }
    });

    function changePage(page: number, perPage?: number | string) {
      self.page = page;
      perPage && (self.perPage = parseInt(perPage as string, 10));
    }

    function selectAction(action: Action) {
      self.selectedAction = action;
    }

    const saveRemote: (
      api: Api,
      data?: object,
      options?: fetchOptions
    ) => Promise<any> = flow(function* saveRemote(
      api: Api,
      data: object,
      options: fetchOptions = {}
    ) {
      try {
        options = {
          method: 'post', // 默认走 post
          ...options
        };

        self.markSaving(true);
        const json: Payload = yield getEnv(self).fetcher(api, data, options);
        self.markSaving(false);

        if (!isEmpty(json.data) || json.ok) {
          self.updateData(
            normalizeApiResponseData(json.data),
            {
              __saved: Date.now()
            },
            !!api && (api as ApiObject).replaceData
          );
          self.updatedAt = Date.now();
        }

        if (!json.ok) {
          self.updateMessage(
            json.msg ?? options.errorMessage ?? self.__('saveFailed'),
            true
          );
          getEnv(self).notify(
            'error',
            self.msg,
            json.msgTimeout !== undefined
              ? {
                  closeButton: true,
                  timeout: json.msgTimeout
                }
              : undefined
          );
          throw new ServerError(self.msg);
        } else {
          self.updateMessage(json.msg ?? options.successMessage);
          self.msg &&
            getEnv(self).notify(
              'success',
              self.msg,
              json.msgTimeout !== undefined
                ? {
                    closeButton: true,
                    timeout: json.msgTimeout
                  }
                : undefined
            );
        }
        return json.data;
      } catch (e) {
        self.markSaving(false);

        if (!isAlive(self) || self.disposed) {
          return;
        }

        e.type !== 'ServerError' && getEnv(self).notify('error', e.message);
        throw e;
      }
    });

    const setAdvancedFilter = (list: any) => {
      self.advancedFilter = list
    }

    const setAdvancedFilterOriginal = (list: any) => {
      self.advancedFilterOriginal = list
    }

    const setCurCardId = (carId: string) => {
      self.curCardId = carId;
    }

    const setCurAdFilterId = (filterId: null | string) => {
      self.curAdFilterId = filterId;
    }

    const setAdFilterToggable = (toggable: boolean) => {
      self.adFilterToggable = toggable;
    }


    const setFilterTogglable = (toggable: boolean, filterVisible?: boolean) => {
      self.filterTogggable = toggable;

      filterVisible !== void 0 && (self.filterVisible = filterVisible);
    };

    const setFilterVisible = (visible: boolean) => {
      self.filterVisible = visible;
    };

    const setSelectedItems = (items: Array<any>) => {
      self.selectedItems.replace(items);
    };

    const setUnSelectedItems = (items: Array<any>) => {
      self.unSelectedItems.replace(items);
    };

    const setInnerModalOpened = (value: boolean) => {
      self.hasInnerModalOpen = value;
    };

    const initFromScope = function (scope: any, source: string) {
      let rowsData: Array<any> = resolveVariableAndFilter(
        source,
        scope,
        '| raw'
      );

      if (!Array.isArray(rowsData) && !self.items.length) {
        return;
      }

      rowsData = Array.isArray(rowsData) ? rowsData : [];

      const data = {
        ...self.pristine,
        items: rowsData,
        count: 0,
        total: 0
      };

      self.items.replace(rowsData);
      self.reInitData(data);
    };

    const exportAsCSV = async (
      options: {loadDataOnce?: boolean; api?: Api; data?: any} = {}
    ) => {
      let items = options.loadDataOnce ? self.data.itemsRaw : self.data.items;

      if (options.api) {
        const env = getEnv(self);
        const res = await env.fetcher(options.api, options.data);
        if (!res.data) {
          return;
        }
        if (Array.isArray(res.data)) {
          items = res.data;
        } else {
          items = res.data.rows || res.data.items;
        }
      }

      import('papaparse').then((papaparse: any) => {
        const csvText = papaparse.unparse(items);
        if (csvText) {
          const blob = new Blob(
            // 加上 BOM 这样 Excel 打开的时候就不会乱码
            [new Uint8Array([0xef, 0xbb, 0xbf]), csvText],
            {
              type: 'text/plain;charset=utf-8'
            }
          );
          saveAs(blob, 'data.csv');
        }
      });
    };


    const adFilterRequest: (
      api: Api,
      data?: object,
      options?: fetchOptions & {
        forceReload?: boolean;
        loadDataOnce?: boolean; // 配置数据是否一次性加载，如果是这样，由前端来完成分页，排序等功能。
        loadDataOnceFetchOnFilter?: boolean; // 在开启loadDataOnce时，filter时是否去重新请求api
        source?: string; // 支持自定义属于映射，默认不配置，读取 rows 或者 items
        loadDataMode?: boolean;
        syncResponse2Query?: boolean;
      }
    ) => Promise<any> = flow(function* filterAdd(
      api: Api,
      data: object,
      options: fetchOptions = {}
    ){
      try {

        const ctx: any = {
          ...data
        }

        const json: Payload = yield getEnv(self).fetcher(api, ctx, {
          ...options,
        });

        if (!json.ok) {
          self.updateMessage(
            json.msg ?? options.errorMessage ?? self.__('CRUD.fetchFailed'),
            true
          );
          getEnv(self).notify(
            'error',
            json.msg,
            json.msgTimeout !== undefined
              ? {
                  closeButton: true,
                  timeout: json.msgTimeout
                }
              : undefined
          );
        } else {
          if (!json.data) {
            throw new Error(self.__('CRUD.invalidData'));
          }

        }
        return json;
      } catch (e) {
        const env = getEnv(self) as IRendererStore;

        if (!isAlive(self) || self.disposed) {
          return;
        }

        self.markFetching(false);

        if (env.isCancel(e)) {
          return;
        }

        console.error(e.stack);
        env.notify('error', e.message);
        return;
      }
    })

    const getAdFilter = () => {
      let _advancedFilter = self.advancedFilter.slice()
      let curAdFilterId = self.curAdFilterId;
      if(!curAdFilterId) return {}

      let filterContent = _advancedFilter.filter(v=> v.CARD_ID === curAdFilterId)[0]?.CARD_CONTENT;

      if(!filterContent)return {}

      // 过滤掉 没有填值的条件
      var filterData = filterContent.map(function(group: any){
        return group.reduce(function(mo: any[], item: any){
            let { typeValue, value } = item; 
            value = Array.isArray(value)? value: [];
            value = value.filter((v:any) => v || v === 0);
            if(!~['is null', 'is not null'].indexOf(typeValue) && !value.length){
            }else if('between' === typeValue && value.length !== 2){
            }else {
                mo.push(item)
            }
            return mo
        }, [])
      }).filter((v: any)=> v.length)

      if(!filterData.length)return {};

      return {
        adFilter: filterData
      }
    }

    const setDynamicFieldKey = (value: string | null) => {
      self.dynamicFieldKey = value;
    }

    const setDynamicFieldValue = (value: string | number | null) => {
      self.dynamicFieldValue = value;
    }

    const getDynamicField = () => {
      if(!self.dynamicFieldKey || (!self.dynamicFieldValue && self.dynamicFieldValue !== 0))return {}

      return {
        [self.dynamicFieldKey]: self.dynamicFieldValue
      }
    }

    const setLayoutMode = (mode: LayoutModeEnum) => {
      self.layoutMode = mode
    }

    return {
      setPristineQuery,
      updateQuery,
      fetchPreData,
      fetchInitData,
      changePage,
      selectAction,
      saveRemote,
      setFilterTogglable,
      setFilterVisible,
      setSelectedItems,
      setUnSelectedItems,
      setInnerModalOpened,
      initFromScope,
      exportAsCSV,
      setAdFilterToggable,
      setCurCardId,
      setCurAdFilterId,
      setAdvancedFilter,
      setAdvancedFilterOriginal,
      adFilterRequest,
      getAdFilter,
      setDynamicFieldKey,
      setDynamicFieldValue,
      getDynamicField,
      setLayoutMode,
    };
  });

export type ICRUDStore = Instance<typeof CRUDStore>;
