import html2canvas from 'html2canvas'
import { message } from 'antd'
import * as service from '../services/index'
import parseChartOption from './parseChartOption'
import moment from 'moment'
import URLS from '../constants/url'

/**
 * 获得看板中图表的真实过滤规则
 */
function getTrueFilters(item, filters, relationColumns) {
    let trueFilters = [];
    filters.forEach(f => {
        relationColumns.forEach(rc => {
            if(f.name === rc.code) {
                rc.relations.forEach(re => {
                    if(re.dataSource.code === item.dataSourceCode) {
                        trueFilters.push({
                            name: re.column.name,
                            operator: f.operator,
                            type: re.column.type,
                            value1: f.value1,
                            value2: f.value2,
                            using: f.using
                        });
                    }
                });
            }
        });
    });
    return trueFilters;
}

function getBodyFilters(filters) {
    return filters.filter(f => f.using).map(f => {
        let { name, operator, type, value1, value2 } = f;
        let bodyFilter = {
            columnName: name,
            columnType: type,
            symbol: operator,
            value: value1
        };
        if(type === 'scale' && operator === 'between') {
            bodyFilter['value'] = value1 + ',' + value2;
        }else if(type === 'time') {
            let v1 = moment(value1).format('YYYY-MM-DD');
            let v2 = moment(value2).format('YYYY-MM-DD');

            if(operator === 'between') {
                bodyFilter['value'] = v1 + ',' + v2;
            }else {
                bodyFilter['value'] = v1;
            }
        }
        return bodyFilter;
    }); 
}

export default {
    namespace: 'dashboardDesigner',
    state: {
        originData: {
            code: null,
            name: '无标题',
            items: [],
            description: '',
            thumbnail: '',
            dirty: false,
            editMode: true,
            filterColumns: [],
            filters: [],
            dataSources: [],
            relationColumns: [],
            columnFetching: false,
            loading: false,
        },
        name: '无标题',
        defaultLayout: { x: 0, y: 50, w: 12, h: 6, minW: 2, maxW: 12, minH: 1 },
        items: [],
        description: '',
        thumbnail: '',
        dirty: false,
        editMode: true,
        filterColumns: [],
        filters: [],
        dataSources: [], // 图表关联的所有数据源
        relationColumns: [], // 自定义的列
        columnFetching: false,
        loading: false,
    },
    
    reducers: {
        silentSetField(state, action) {
            const { name, value } = action;
            let obj = {};
            obj[name] = value;
            let newState = Object.assign({}, state, obj);
            return newState;
        },
        setField(state, action) {
            const { name, value } = action;
            let obj = {};
            obj[name] = value;
            let newState = Object.assign({}, state, obj);
            return Object.assign({}, newState, {dirty: true});
        },
        silentSetFields(state, action) {
            const { fields } = action;
            let obj = {};
            fields.map(f => (obj[f.name] = f.value));
            let newState = Object.assign({}, state, obj);
            return newState;
        },
        setFields(state, action) {
            const { fields } = action;
            let obj = {};
            fields.map(f => (obj[f.name] = f.value));
            let newState = Object.assign({}, state, obj);
            return Object.assign({}, newState, {dirty: true});
        },
        addChart(state, action) {
            let { items, dataSources, defaultLayout } = state;
            const { chart } = action;

            items = items.concat([{
                code: chart.code,
                chartCode: chart.code,
                name: chart.name,
                creatorCode: chart.creatorCode,
                creatorName: chart.creatorName,
                dataSourceCode: chart.dataSourceCode+'',
                dataSourceName: chart.dataSourceName,
                viewType: 'chart',
                chartType: chart.type,
                filters: chart.filters,
                layout: defaultLayout,
            }]);
            dataSources.findIndex(d => d.code === chart.dataSourceCode+'') === -1 && dataSources.push({
                code: chart.dataSourceCode+'',
                name: chart.dataSourceName
            });
            return Object.assign({}, state, {items, dataSources, dirty: true});
        },
        addCharts(state, action) {
            let { items, dataSources, defaultLayout } = state;
            const { charts } = action;

            items = items.concat(charts.map(c => {
                dataSources.findIndex(d => d.code === c.dataSourceCode+'') === -1 && dataSources.push({
                    code: c.dataSourceCode+'',
                    name: c.dataSourceName
                });
                return {
                    code: c.code,
                    chartCode: c.code,
                    name: c.name,
                    creatorCode: c.creatorCode,
                    creatorName: c.creatorName,
                    viewType: 'chart',
                    chartType: c.type,
                    dataSourceCode: c.dataSourceCode+'',
                    dataSourceName: c.dataSourceName,
                    filters: c.filters,
                    layout: defaultLayout,
                }
            }));
            return Object.assign({}, state, {items, dataSources, dirty: true});
        },
        deleteItem(state, action) {
            let { items, dataSources, relationColumns, dirty } = state;
            const { item } = action;
            let count = 0;
            let targetIndex = -1;
            for(let i = 0; i < items.length; i++) {
                let tempItem = items[i];
                if(tempItem.dataSourceCode === item.dataSourceCode) {
                    count++;
                }
                if(tempItem.code === item.code) {
                    targetIndex = i; 
                }
            }

            if(count === 1) {
                // 找到只有被删除的item使用的数据源并删除
                let idx = dataSources.findIndex(d => d.code === item.dataSourceCode);
                dataSources.splice(idx, 1);
                // 同时删除已定义的关联字段
                relationColumns.forEach(rc => {
                    rc.relations.forEach((r, x) => {
                        if(r.dataSourceCode === item.dataSourceCode) {
                            rc.relations.splice(x, 1);
                        }
                    })
                });
            }
            if(targetIndex !== -1) {
                items.splice(targetIndex, 1);
            }
            return { ...state, dirty: dirty, items, dataSources };
        },
        addRichText(state, action) {
            let { items, defaultLayout } = state;
            items.push({
                code: Math.random(),
                viewType: 'richText',
                name: '',
                layout: defaultLayout
            });
            return Object.assign({}, state, {items, dirty: true});
        },
        changeLayout(state, action) {
            const { layout } = action;
            let { items, dirty } = state;
            const ly = ['x', 'y', 'w', 'h'];
            for(let i = 0; i < items.length; i++) {
                if(layout[i]) { // 非删除引起
                    for(let j = 0; j < ly.length; j ++) {
                        if(items[i].layout[ly[j]] !== layout[i][ly[j]]) {
                            dirty = true;
                            items[i].layout[ly[j]] = layout[i][ly[j]];
                        }
                    }
                }else { // 删除引起
                    dirty = true;
                }
            }
            return Object.assign({}, state, {items, dirty});
        },
        // 富文本用
        modifyItem(state, action) {
            let { fields } = action;
            let { items } = state;
            let dirty = false;
            for(let i = 0; i < items.length; i++) {
                if(items[i].code === fields.code) {
                    for(let k in fields) {
                        items[i][k] = fields[k];
                        dirty = true;
                    }
                }
            }
            return Object.assign({}, state, {items, dirty});
        },
        reset(state, action) {
            let newState = Object.assign({}, state, state.originData);
            return Object.assign({}, newState);
        },
        setEditMode(state, action) {
            const { checked } = action;
            return { ...state, editMode: checked };
        },
        addRelationColumn(state, action) {
            const { relationColumns } = state;
            relationColumns.push({
                code: Math.random()+'',
                name: '新字段',
                relations: []
            });
            return { ...state, relationColumns, dirty: true };
        },
        deleteRelationColumn(state, action) {
            const { code } = action;
            const { relationColumns } = state;
            let index = relationColumns.findIndex(r => r.code === code);
            relationColumns.splice(index, 1);
            console.log(relationColumns);
            return { ...state, relationColumns, dirty: true };
        },
        setRelationColumn(state, action) {
            const { code, relationColumn } = action
            const { relationColumns } = state;
            let index = relationColumns.findIndex(r => r.code === code);
            relationColumns[index] = relationColumn;
            return { ...state, relationColumns, dirty: true };
        },
        setItemFetching(state, action) {
            const { code, fetching } = action
            const { items } = state;
            let index = items.findIndex(item => item.code === code);
            items[index] = {
                ...items[index],
                fetching
            };
            return { ...state, items };
        },
        setItemChartOption(state, action) {
            const { code, chartOption } = action
            const { items } = state;
            let index = items.findIndex(item => item.code === code);
            items[index] = {
                ...items[index],
                chartOption
            };
            return { ...state, items };
        }
    },

    effects: {
        *remoteGetColumns(action, { call, put, select }) {
            const { dataSourceCode, mandatory } = action;
            const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
            const { dataSources } = dashboardDesigner;
            const body = dataSourceCode;
            let idx = dataSources.findIndex(d => d.code === dataSourceCode);
            if(!mandatory && dataSources[idx].columns && dataSources[idx].columns.length > 0) {
                return;
            }
            

            try {
                const res = yield call(service.fetch, {
                    url: URLS.DATASOURCE_QUERY_DATACOLUMNS,
                    body: body
                });
                console.log('获得列数据', body, res);
                if(!res.err && res.data.code > 0) {
                    let resData = res.data.data;
                    
                    let columns = resData.map((c, i) => {
                        return {
                            key: i,
                            name: c.columnName,
                            label: c.columnRaname,
                            type: c.columnType,
                            groupable: c.isGroup==='1'?true:false,
                            filterable: c.isFilter==='1'?true:false,
                            bucketizable: c.isSubsection==='1'?true:false,
                            selection: []
                        }
                    })
                    
                    dataSources[idx] = { ...dataSources[idx], columns }
                    yield put({ type: 'silentSetField', name: 'dataSources', value: dataSources });
                }else {
                    message.error('请求列数据失败:' + (res.err || res.data.msg));
                    yield put({ type: 'silentSetField', name: 'dataSources', value: [] });
                }
            }catch(e) {
                console.log(e, body);
                message.error('请求列数据失败: ' + e);
            }
        },
        *changeFilters(action, { put, call, select }) {
            const { filters } = action;
            const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
            const { items, relationColumns } = dashboardDesigner;

            // 找到filters影响的数据源id
            let targetDataSource = [];
            filters.forEach(f => {
                relationColumns.forEach(rc => {
                    if(f.name === rc.code) {
                        let dataSource = rc.relations.map(re => re.dataSource);
                        targetDataSource = dataSource;
                    }
                });
            });
            // 找到filters有影响的item
            let targetItems = items.filter(item => !!targetDataSource.find(d => d.code === item.dataSourceCode));
            yield put({ type: 'silentSetField', name: 'filters', value: filters });
            
            for(let i = 0; i < targetItems.length; i++) {
                yield put({ type:'fetchChartData', item: targetItems[i], mandatory: true });
            }
        },
        *fetchChartData(action, { put, call, select }) {
            const { item, mandatory } = action;
            const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
            const { filters, relationColumns } = dashboardDesigner;
            const { chartCode, chartType } = item;
            const body = {
                dashCreateId: chartCode,
                filters: getBodyFilters(getTrueFilters(item, filters, relationColumns))
            };
            if(!mandatory && !!item.chartOption) {
                return;
            }

            try {
                yield put({ type: 'setItemFetching', code: chartCode, fetching: true });
                const res = yield call(service.fetch, {
                    url: URLS.CHART_OPTION,
                    body,
                    timeout: 30000
                });
                console.log('看板请求图表展示数据', body, res);
                if(!res.err && res.data.code > 0) {
                    let resData = res.data.data;
                    let chartOption = parseChartOption(chartType, resData, JSON.parse(resData.chartsConfig));
                    
                    yield put({ type: 'setItemChartOption', code: chartCode, chartOption });
                }else {
                    yield put({ type: 'setItemChartOption', code: chartCode, chartOption: {} });
                    console.error(body, res.err || res.data.msg);
                    message.error('请求图表展示数据失败: ' + (res.err || res.data.msg));
                }
            }catch(e) {
                console.error(body, e);
                yield put({ type: 'setItemChartOption', code: chartCode, chartOption: {} });
                message.error('请求图表展示数据失败: ' + e);
            }finally {
                yield put({ type: 'setItemFetching', code: chartCode, fetching: false });
                // 主动触发一次window的resize事件
                window.setTimeout(() => {
                    var e = document.createEvent("Event");
                    e.initEvent("resize", true, true);
                    window.dispatchEvent(e);
                }, 300);
            }
        },
        *saveWithThumbnail(action, {put, call}) {
            try {
                let thumbnail;
                yield put({ type: 'silentSetField', name: 'loading', value: true });
                let canvas = yield html2canvas(document.getElementsByClassName('viewlayout')[0]);
                thumbnail = canvas.toDataURL('image/png', 1.0);
                yield put({ type: 'setField', name: 'thumbnail', value: thumbnail });
                yield put({ type: 'dashboard/remoteModify' });
                yield put({ type: 'silentSetField', name: 'loading', value: false });
            }catch(e) {
                console.log(e);
                message.error('生成缩略图失败: ' + e);
            }
        }
    },
    subscription: {

    },
};

