import {reactive, computed} from "vue"
import { DesignComp } from "../../defines/DesignTemp/DesignComp"
import { cloneDeep } from "lodash";

type CreateFunc = (values:any, comm?: Partial<CommPropType>)=>DesignComp;

export class CompController{
    state = reactive({
        _id: "",
        title: "",
        pageStyle: {}, 
        content: [] as DesignComp[]
    })
    //包括所有部件和所有列表的
    designCompMap = new Map<string, DesignComp>();  
    CompTypes = [] as  {type:string, name:string, thumbnail:string, isBasic: boolean, createCompData: CreateFunc}[];

    initPageData(designData:any) {
        this.state._id = designData._id;
        this.state.title = designData.title;
        this.state.pageStyle = designData.pageStyle;
        this.state.content = designData.content || [];
        const arr = this.state.content;
        this.designCompMap.clear();

        const ParseComp = (obj:any)=> {
            if (typeof obj != "object") return;
            //作为组件
            if (obj.id && obj.compKey && obj.value) {
               this.designCompMap.set(obj.id, obj);
            } else {
                for (const c in obj) {
                    ParseComp(obj[c]);
                }
            }
        }

        let index = arr.length
        while (index--) {
            const item = arr[index];
            ParseComp(item.value)
            this.designCompMap.set(item.id, item);
        }
    }

    insertDesignContent(compKey: string, index?: number) {
        index === undefined && (index = this.state.content.length);
        const comp = this.createCompData(compKey);
        if (!comp) return;
       
        this.state.content.push( comp );
        return comp;
    }

    insertCompContainer(compKey: string, container: DesignComp) {
        const compData = this.createCompData(compKey) 
        if (!compData) {
           console.error("没有找到对应的组件")
           return;
        }
        container.value.children || (container.value.children = []);
        container.value.children.push( compData );
        
        return compData;
    }

    createCompData(compKey: string) {
        const CompType =  this.CompTypes.find(item=>item.type == compKey);
        if (!CompType) return;


        return CompType.createCompData(this.isText(compKey) ? "": {});
    }

    isText(compKey:string) {
        return compKey == "Text";
    }

    getCompType(compKey:string) {
        return  this.CompTypes.find(item=>item.type == compKey);
    }

    setCompState(compId: string , data:any) {
        this.designCompMap.set(compId, data);
    }
    getCompState(compId:string )  {
        return this.designCompMap.get(compId) as DesignComp;
    }
}

export const CompCtrl = new CompController();

type CommPropType = Pick<DesignComp, "compKey" | "background" | "layout" | "id">
export function RegCompType<T>(info: {type:string , name:string, thumbnail:string, isBasic?:boolean},  getDef:(Partial<CommPropType> & {value: T})|(()=>Partial<CommPropType> & {value: T})) {
    info.isBasic = info.isBasic ? true : false;
    
    const createCompData =  function(values: Partial<T>, comm?: Partial<CommPropType>) {
        const defvalues = typeof getDef == "function" ? getDef(): cloneDeep(getDef);
        defvalues.compKey = info.type as any
        
        const isStrValue = (typeof values == "string" || typeof defvalues.value == "string");
        if (isStrValue && values) {
            //@ts-ignore
            defvalues.value = values;
        }
        const c = Object.assign({}, defvalues, comm) as CommPropType &{value: T}
         if (!isStrValue &&  values != null ) {
            c.value = {...c.value, ...values}
        }
        const ret = new DesignComp(c) as typeof c;
        const out = reactive(ret)
        CompCtrl.setCompState(ret.id, out);

        return out;
    }

    type ValueType = ReturnType<typeof createCompData>

    function useCompData(compId: string) {
        return CompCtrl.getCompState(compId) as ValueType;
    }

    //@ts-ignore
    info.createCompData = createCompData;

    if (!CompCtrl.CompTypes.find(item=>item.type == info.type)) {
        CompCtrl.CompTypes.push(info as any);
    }

    return {useCompData, createCompData}
}