import { Action } from '@action-land/core';
import { ComponentProps } from '../types/componentProps';
import { LActionTypes } from '../types/extractActionType';
import { LObjectValues } from '../types/extractValueType';
import { LActionValueForType } from '../types/extractValueTypeFromAction';
import { LActionValueForTypeWithDefault } from '../types/extractValueTypeFromActionWithDefault';
import { mergeProps } from '../types/mergeProps';
import { iChildren } from '../types/pickChildrenType';
import { iActions } from '../types/pickIActionsType';
import { iState } from '../types/pickIStateType';
import { oActions } from '../types/pickOActionType';
import { oView } from '../types/pickOutputViewType';
import { iProps } from '../types/pickPropType';
import { Component } from './component';
import { ListComponentState } from './listComponentState';
/**
 * Creates a new component-type with the overridden props
 */
export declare type iComponentNext<P, S> = ComponentNext<mergeProps<P, S>>;
/**
 * Removes duplicate A | A insertions.
 */
export declare type U<A, B> = A | B extends A & B ? A : A | B;
/**
 * API for type safe and composable components that are agnostic of view library
 */
export declare class ComponentNext<P1 extends ComponentProps> {
    readonly _init: () => any;
    readonly _update: (a: Action<unknown>, b: unknown) => any;
    readonly _command: (a: Action<unknown>, b: unknown) => unknown;
    readonly _view: (e: unknown, s: unknown, p: unknown) => unknown;
    private readonly _children;
    private readonly _iActions;
    /**
     * @param _init Function which returns initial state of the component
     * @param _update Function which takes action and state, and returns new state
     * @param _command Function which takes action and state, and returns new action
     * @param _view Function which returns view based on state and props
     */
    private constructor();
    /**
     * Transform ComponentNext P1 to ComponentNext P2
     * @param fn mapper function to transform component
     */
    lift<P2>(fn: (c: ComponentNext<P1>) => ComponentNext<P2>): ComponentNext<P2>;
    /**
     * Create new component with provided value as initial state
     *
     * ```typescript
     * import {ComponentNext} from '@action-land/component'
     *
     * const component = ComponentNext.lift({count: 100})
     * ```
     * @param state initial state of component
     */
    static lift<S>(state: S): ComponentNext<{
        iState: S;
        oView: void;
    }>;
    /**
     * Create new component with state as undefined
     *
     * ```typescript
     * import {ComponentNext} from '@action-land/component'
     *
     * const component = ComponentNext.empty
     * ```
     */
    static readonly empty: ComponentNext<{
        iState: undefined;
        oView: void;
    }>;
    /**
     * Add transformation of component's state for a given action
     * p.s: Check out test cases for advanced use cases
     *
     * ```typescript
     * import {ComponentNext} from '@action-land/component'
     *
     * const component = ComponentNext.lift({count: 100})
     *  .matchR('add', (value: number, state) => ({count: state.count + value}))
     *  // Adds behaviour to handle action of type Action<number, 'add'>
     * ```
     * @typeparam T Action type to be handled by component
     * @typeparam V Value of action to be handled by component
     * @param type Action type for which we want to add behaviour
     * @param cb Transformation function that returns a new state
     */
    matchR<T extends string | number, V>(type: T, cb: (value: LActionValueForTypeWithDefault<iActions<P1>, T, V>, state: iState<P1>) => iState<P1>): iComponentNext<P1, {
        iActions: Action<LActionValueForTypeWithDefault<iActions<P1>, T, V>, T> | iActions<P1>;
    }>;
    /**
     * Add ability to return new action on matching action
     *
     *```typescript
     * import {ComponentNext} from '@action-land/component'
     * import {Action} from '@action-land/core'
     *
     * const component = ComponentNext.lift({count: 100})
     *  .matchC('persist', (value: number, state) => (Action.of('writeCache', value)))
     *  // Adds behaviour to handle action of type Action<number, 'persist'>
     * ```
     * @typeparam T Action type to be handled by component
     * @typeparam V Type of action value to be handled by component
     * @typeparam T2 Action type fired by cb function
     * @typeparam V2 value of action fired by cb function
     * @param type Action type for which we want to add behaviour
     * @param cb Function that returns new action
     */
    matchC<T extends string | number, V, V2, T2 extends string | number>(type: T, cb: (value: LActionValueForTypeWithDefault<iActions<P1>, T, V>, state: iState<P1>) => Action<V2, T2>): iComponentNext<P1, {
        iActions: Action<LActionValueForTypeWithDefault<iActions<P1>, T, V>, T> | iActions<P1>;
        oActions: oActions<P1> | Action<V2, T2>;
    }>;
    /**
     * Add component as a child of a given component i.e
     * 1. Forward all actions with type of child's name to child component update function
     * 2. maintain self-state and child's state separately
     *
     * ```typescript
     * import {ComponentNext} from '@action-land/component'
     *
     * const child1 = ComponentNext.lift({c1: 100})
     * const child2 = ComponentNext.lift({c2: 200})
     * const component = ComponentNext.lift({c: 1000})
     *  .install(
     *  {
     *    child1, // actions of type `child1` will be forwarded to child1 component
     *    child2  // actions of type `child2` will be forwarded to child2 component
     *  }
     * )
     *
     * component._init()
     * //outputs
     * //{
     * // node: {c: 1000},
     * // children: {
     * //   child1: {c1: 100},
     * //   child2: {c2: 200}
     * // }
     * //}
     *
     * ```
     * @param spec key value pair object of child name and child component
     *
     */
    install<S extends {
        [k: string]: ComponentNext<any>;
    }>(spec: S): iComponentNext<P1, {
        iState: {
            node: iState<P1>;
            children: {
                [k in keyof typeof spec]: iState<typeof spec[k]>;
            };
        };
        iChildren: S;
        iActions: iActions<P1> | LObjectValues<{
            [k in keyof S]: S[k] extends ComponentNext<infer P2> ? Action<iActions<P2>, k> : never;
        }>;
        oActions: oActions<P1> | LObjectValues<{
            [k in keyof S]: S[k] extends ComponentNext<infer P2> ? Action<oActions<P2>, k> : never;
        }>;
    }>;
    /**
     * Adds presentation logic to the component
     * 1. Create view based on props and state
     *
     * ```typescript
     * import {ComponentNext} from '@action-land/component'
     *
     * const component1 = ComponentNext.lift(10)
     *   .render((_, props: string) => [props, _.state + 1])
     *
     * component._view({}, component._init(), 'Hello') // output: [Hello, 11]
     * ```
     * 2. Can invoke child component's view
     *
     * ```typescript
     * import {ComponentNext} from '@action-land/component'
     *
     * const component = ComponentNext.lift('Hello')
     *   .install({
     *     child: ComponentNext.lift('World').render((_, p: string) => p)
     *   })
     *   .render((_, p: string) => [p, _.children.child('World')]
     *
     * component._view({}, component._init(), 'Hello') // output: [Hello, World]
     * ```
     * 3. Can emit action
     *
     * ```typescript
     * import {ComponentNext} from '@action-land/component'
     *
     * const component = ComponentNext.lift(10)
     *   .matchR('add', (a: number, s) => s + a)
     *   .render(_ => _.actions.add(100))
     *
     * component._view({}, component._init()) // output: Action<100, 'add'> and changes component state to 110
     * ```
     * @typeparam P View prop type
     * @typeparam V View representation data structure type
     * @param cb Function which return view based on props and state
     */
    render<P = never, V = unknown>(cb: (env: {
        actions: {
            [k in LActionTypes<iActions<P1>>]: (e: LActionValueForType<iActions<P1>, k>) => unknown;
        };
        state: iState<P1>;
        children: {
            [k in keyof iChildren<P1>]: iProps<iChildren<P1>[k]> extends never ? () => oView<iChildren<P1>[k]> : (p: iProps<iChildren<P1>[k]>) => oView<iChildren<P1>[k]>;
        };
    }, p: P) => V): iComponentNext<P1, {
        oView: V;
        iProps: P;
    }>;
    /**
     * Transform initial state of the component
     *
     * ```typescript
     *
     * import {ComponentNext} from '@action-land/component'
     *
     * ComponentNext.lift({count: 100}).configure(iState => ({
     *  count: iState.count * 2
     * }))
     *
     * const component._init() // output: {count: 200}
     * ```
     * @typeparam S2 State type post transformation
     * @param fn function to transform the state
     *
     */
    configure<S2 extends iState<P1>>(fn: (a: iState<P1>) => S2): iComponentNext<P1, {
        iState: S2;
    }>;
    toList<T extends string | number>(fn: (p: iProps<P1>) => T): iComponentNext<P1, {
        iState: ListComponentState<iState<P1>>;
        iActions: Action<iActions<P1>, T>;
        oActions: Action<oActions<P1>, T>;
    }>;
    /**
     * Method to convert old component API to ComponentNext
     * @typeparam A state
     * @typeparam V view
     * @typeparam P prop
     * @typeparam I init param
     */
    static from<A, V, P, I extends unknown[]>(component: {
        init: (...t: I) => A;
        update: (a: any, s: any) => any;
        command: (a: any, s: any) => any;
        view: (e: any, s: any, p: P) => V;
    }, ...initParams: I): ComponentNext<{
        iState: A;
        oView: V;
        iProps: P;
    }>;
    /**
     * Method to convert componentNext to old component API
     */
    readonly component: Component<iState<P1>, iProps<P1>, [], oView<P1>>;
}
