/**
 * @since Last modified: 2024/06/20 21:06:09
 * @function createModule
 * @param {string} attr  - one attribute of element.
 * @param {string} value  - The value corresponding to the attribute.
 * @param {array} map  - The options map.
 * @returns {Object} - Return a object.
 * @see {@link https://codepen.io/axui/pen/KKJQRwG|demo @ codepen}
 * @example
 * ax.createModule('length','30');
 * <!--return {length:30}-->
 */



'use strict';

import { T_obj, T_sel } from "../../../types/ax";
import { T_module } from "../../../types/utils";
import ax from "../ax";
import PubBase from "../modules/PubBase";
import PubCommon from "../modules/PubCommon";
import PubListen from "../modules/PubListen";
import PubUpdate from "../modules/PubUpdate";
import deepClone from "./deepClone";
import elProps from "./elProps";
import getDataType from "./getDataType";
import getEl from "./getEl";
import getOptsFromMap from "./getOptsFromMap";
import instance from "./instance";
import pipe from "./pipe";



const createModule = <T>({ name, maps = [],
    ready = null,
    events = {},
    members = {},
    methods = {},
    type = 'none',
    component = false,
    
    
    
    updatable = true,
}: T_module) => {
    let NewModule = null,
        BaseMudule = updatable ? pipe(PubListen, PubUpdate, PubCommon)(PubBase) : pipe(PubListen, PubCommon)(PubBase),
        initFrag = function (this: T_obj) {
            
            Reflect.deleteProperty(members, 'moduleName');
            Reflect.deleteProperty(events, 'moduleName');
            
            if (updatable) {
                
                this.storKeys = this.getStorageKeys;
                
                dftOpts = deepClone(this.options);
                
                this.createProxy();
            }
            
            this.plans = {};
            
            instance.push(this, this.options.insName, this.moduleName.toLowerCase());
            
            for (let k in members) {
                
                getDataType(members[k]) === 'Function' ? members[k].bind(this) : null;
                this[k] = members[k];
            }
            
            Object.assign(this, events);
            
            this.on('init', () => {
                this.destroyed = false;
            });
            
            ready && ready.call(this);
        };
        let moduleMap = {
            'dom':class MuduleWithDomHost extends BaseMudule {
                constructor(el: T_sel, options?: T) {
                    super();
                    
                    this.moduleName = name;
                    
                    this.targetEl = getEl(el);
                    if (!this.targetEl) { return this };
                    
                    elProps(this.targetEl)?.add(this.moduleName);
                    
                    this.options = this.mergeOpts({
                        
                        source: options,
                        
                        map: maps,
                        
                        el: this.targetEl,
                        
                        component: type !== 'dom' ? false : component,
                    });
                    
                    this.rawHtml = this.targetEl.innerHTML;
                    
                    this.cmptAttrs = [];
                    
                    initFrag.call(this);
                    
                    
                    
                    
                }
            },
            'doms':class MuduleWithDomsHost extends BaseMudule {
                constructor(el: T_sel, options?: T_obj) {
                    super();
                    
                    this.moduleName = name;
                    
                    this.targetEl = getEl(el);
                    if (!this.targetEl) { return this };
                    
                    elProps(this.targetEl)?.add(this.moduleName);
                    
                    this.options = this.mergeOpts({
                        
                        source: options,
                        
                        map: maps,
                        
                        el: this.targetEl,
                        
                        component: type !== 'dom' ? false : component,
                    });
                    
                    this.rawHtml = this.targetEl.innerHTML;
                    
                    this.cmptAttrs = [];
                    
                    initFrag.call(this);
                    
                    
                    
                    
                }
            },
            'data':class MuduleWithDataHost extends BaseMudule {
                constructor(data: any, options?: T_obj) {
                    super();
                    
                    this.moduleName = name;
                    
                    this.targetData = data;
                    this.options = this.mergeOpts({
                        source: options,
                        map: maps,
                    });
                    initFrag.call(this);
                }
            },
            'none':class MuduleWithNoneHost extends BaseMudule {
                constructor(options: T) {
                    super();
                    
                    this.moduleName = name;
                    this.options = this.mergeOpts({
                        source: options,
                        map: maps,
                    });
                    initFrag.call(this);
                }
            }
        }
    if (type === 'dom') {
        NewModule = class MuduleWithDomHost extends BaseMudule {
            constructor(el: T_sel, options?: T_obj) {
                super();
                
                this.moduleName = name;
                
                this.targetEl = getEl(el);
                if (!this.targetEl) { return this };
                
                elProps(this.targetEl)?.add(this.moduleName);
                
                this.options = this.mergeOpts({
                    
                    source: options,
                    
                    map: maps,
                    
                    el: this.targetEl,
                    
                    component: type !== 'dom' ? false : component,
                });
                
                this.rawHtml = this.targetEl.innerHTML;
                
                this.cmptAttrs = [];
                
                initFrag.call(this);
                
                
                
                
            }
        };
    } else if (type === 'data') {
        NewModule = class MuduleWithDataHost extends BaseMudule {
            constructor(data: any, options?: T_obj) {
                super();
                
                this.moduleName = name;
                
                this.targetData = data;
                this.options = this.mergeOpts({
                    source: options,
                    map: maps,
                });
                initFrag.call(this);
            }
        };
    } else {
        NewModule = class MuduleWithNoneHost extends BaseMudule {
            constructor(options: T_obj) {
                super();
                
                this.moduleName = name;
                this.options = this.mergeOpts({
                    source: options,
                    map: maps,
                });
                initFrag.call(this);
            }
        };
    }
    
    Reflect.deleteProperty(methods, 'constructor');
    
    Object.assign(moduleMap[type].prototype, methods);
    
    
    moduleMap[type].hostType = type;
    return moduleMap[type];
}
export default createModule;
