import { App } from 'vue-demi';
import { ComputedRef } from 'vue-demi';
import { DefineComponent } from 'vue-demi';
import { EffectScope } from 'vue-demi';
import { Plugin as Plugin_2 } from 'vue-demi';
import { UnwrapRef } from 'vue-demi';

export declare type Actions<A> = {
    readonly [k in keyof A]: A[k] extends (...args: infer P) => infer R ? (...args: P) => R : never;
};

export declare type ActionsTree = Record<string, Method>;

export declare type Computed<C> = {
    readonly [k in keyof C]: C[k] extends (state: any) => infer R ? ComputedRef<R> : never;
};

export declare type ComputedTree<S extends StateTree> = Record<string, ((state: UnwrapRef<S>) => any) | (() => any)>;

export declare function createComponent(useStore: any): DefineComponent;

export declare function createNervue(): NervuePlugin;

/**
 * @param {StoreOptions} options - store definition options object
 * @returns {StoreDefinition} useStore function
 */
export declare function defineStore<Id extends string, S extends StateTree = {}, G = {}, C extends ComputedTree<S> = {}, A = {}>(options: StoreOptions<Id, S, G, C, A>): StoreDefinition<Id, S, G, C, A>;

declare type GuardMethod = (...val: any[]) => {
    next: boolean;
    value?: any;
};

export declare type GuardsTree = Record<string, GuardMethod[]>;

/**
 * @param useStore - store composition
 * @param keys - array of action keys
 */
export declare function mapActions<Id extends string, S extends StateTree, G extends GuardsTree, C extends ComputedTree<S>, A, Keys extends keyof A>(useStore: StoreDefinition<Id, S, G, C, A>, keys: Keys[]): ActionsTree;

/**
 * @param useStore - store composition
 * @param keysMap - action keys map
 */
export declare function mapActions<Id extends string, S extends StateTree, G extends GuardsTree, C extends ComputedTree<S>, A, KeyMapper extends Record<string, keyof A>>(useStore: StoreDefinition<Id, S, G, C, A>, keysMap: KeyMapper): ActionsTree;

/**
 * @param useStore - store composition
 * @param keys - array of state or computed keys
 */
export declare function mapState<Id extends string, S extends StateTree, G extends GuardsTree, C extends ComputedTree<S>, A, Keys extends keyof S | keyof C>(useStore: StoreDefinition<Id, S, G, C, A>, keys: Keys[]): StateTree;

/**
 * @param useStore - store composition
 * @param keysMap - map of state or computed keys
 */
export declare function mapState<Id extends string, S extends StateTree, G extends GuardsTree, C extends ComputedTree<S>, A, KeyMapper extends Record<string, (keyof S | keyof C) | ((store: Store<Id, S, G, C, A>) => any)>>(useStore: StoreDefinition<Id, S, G, C, A>, keysMap: KeyMapper): StateTree;

declare type Method = (...args: any[]) => any;

declare class Nervue {
    installed: boolean;
    _s: Record<string, any>;
    _p: StorePlugin[];
    _e: EffectScope;
    _a: App;
    static sets: any[];
    set(useStore: any): void;
    unset(id: any): void;
    use(plugin: StorePlugin): void;
    install(): void;
}

declare type NervuePlugin = Nervue & Plugin_2;

export declare const nervueSymbol: unique symbol;

declare type PluginContext = {
    store: Store<string, StateTree, GuardsTree, ComputedTree<any>, ActionsTree>;
    options: StoreOptions<string, StateTree, GuardsTree, ComputedTree<any>, ActionsTree>;
};

export declare type State<S> = {
    [k in keyof S]: S[k];
};

export declare type _StateGuards<G extends GuardsTree, K extends string> = Pick<G, K>;

export declare type StateTree = Record<string | number | symbol, any>;

export declare type Store<Id extends string = string, S extends StateTree = {}, G = {}, C = {}, A = {}> = _StoreWithProperties<Id, S, G, C, A> & State<S> & Computed<C> & Actions<A>;

export declare interface StoreDefinition<Id extends string = string, S extends StateTree = {}, G = {}, C = ComputedTree<S>, A = ActionsTree> {
    (): Store<Id, S, G, C, A>;
    $id: Id;
}

export declare interface StoreOptions<Id extends string, S extends StateTree, G = {}, C extends ComputedTree<S> = {}, A = {}> {
    id: Id;
    state?: () => S;
    guards?: G extends GuardsTree ? keyof G extends keyof S ? G : _StoreStateWithGuards<keyof S & string, G> : unknown;
    computed?: C & ThisType<C & A & UnwrapRef<S> & _StoreWithProperties<Id, S, G, C, A>>;
    actions?: A & ThisType<A & C & UnwrapRef<S> & _StoreWithProperties<Id, S, G, C, A>>;
}

declare type StorePlugin = (ctx: PluginContext) => void | Record<string, any>;

declare type _StoreStateWithGuards<K extends string, G> = G extends GuardsTree ? keyof G extends K ? G : _StateGuards<G, K> : unknown;

export declare type _StoreWithProperties<Id, S, G, C, A> = {
    $id: Id;
    $patch(mutator: ((state: UnwrapRef<S>) => void) | Partial<Record<keyof S, any>>): void;
    $subscribe(subscribeOptions: SubscribeOptions<A>): Unsubscribe;
    $state: UnwrapRef<S>;
    _guards: G;
    _computed: [keyof C];
};

export declare type SubscribeOptions<A> = {
    name: keyof A & string;
    detached?: boolean;
    before?(...args: any[]): any;
    after?(...result: any[]): any;
    onError?(error: any): any;
};

export declare type Unsubscribe = () => Promise<boolean>;

export declare function useNervue(): Nervue;

export declare function useStore(id: string): any;
