import { reactive, toRefs, UnwrapNestedRefs } from 'vue'

type Getters<T> = {
    [key in keyof T]: () => unknown
}

interface Store<S extends object, G extends Getters<G>, A extends object, M extends object> {
    state: UnwrapNestedRefs<S>;
    getters: G;
    actions: A;
    methods: M;
}

/**
 * 存储配置项
 */
interface StoreOptions<S extends object, G extends Getters<G>, A extends object, M extends object> {
    state: () => S;
    created?: (context: Store<S, G, A, M>) => void;
    getters?: G & ThisType<Store<S, G, A, M>>;
    actions?: A & ThisType<Store<S, G, A, M>>;
    methods?: M & ThisType<Store<S, G, A, M>>;
}

/**
 * 实例化存储对象
 * @param options 
 * @returns 
 */
export function createStore<S extends object, G extends Getters<G>, A extends object, M extends object>(options: StoreOptions<S, G, A, M>) {
    const state = reactive(options.state())
    const getters = options.getters
    const actions = options.actions

    const methods = {
        $setData: (callback: (state: UnwrapNestedRefs<S>) => void) => {
            callback(state)
        },
        $storeToRefs: () => {
            return toRefs(state)
        },
        ...options.methods,
    }

    const store = {
        state,
        getters,
        actions,
        methods,
    }

    for (const p in actions) {
        const fn = actions[p]
        if (fn instanceof Function) {
            actions[p] = fn.bind(store)
        }
    }

    //options.created && options.created(store)

    return {
        state,
        getters,
        actions,
        methods,
    }
}

const store = createStore({
    state() {
        return {
            id: 0,
            userName: '李兔饼'
        }
    },
    getters: {
        getUserid() {
            return 10086
        }
    },
    actions: {
        getAllEnumList(userid: number) {
            this.state.id = userid
            this.actions.hello()
        },
        hello() {
            console.log('hello world')
        }
    },
})

store.actions?.getAllEnumList(10086)

setTimeout(() => {
    console.log(store.state)
}, 2000);














interface DefineStoreOptions<S extends object, A extends object> {
    state: () => S;
    actions: {
        [key in keyof A]: (context: S, ...args: never) => unknown
    }
}

function defineStore<S extends object, A extends object>(options: DefineStoreOptions<S, A>) {
    const actions = {} as { [key in keyof A]: <T extends unknown[]>(...args: T) => unknown }

    for (const p in options.actions) {
        actions[p] = (...args) => {
            return options.actions[p](options.state(), args as never)
        }
    }

    return {
        actions
    }
}

const dStore = defineStore({
    state() {
        return {
            id: 0,
            userName: '李兔饼'
        }
    },
    actions: {
        getAllEnumList(context, userid: number) {
            //context.id = userid
            return context
        },
    }
})

dStore.actions.getAllEnumList(10086)