import * as React from 'react';
import { IDemoApi } from './demoApi';

export interface DemoComponentProps<TProps = PropDocPropsUnknown> {
    DemoComponent: React.ComponentType<TProps> | React.NamedExoticComponent<TProps>;
    props: TProps;
    isPreview?: boolean;
}

export interface IComponentDocs<TProps> {
    name: string;
    component?: React.ComponentType<TProps> | React.NamedExoticComponent<TProps>;
    props?: PropDoc<TProps, keyof TProps>[];
    contexts?: DemoContext<TProps>[];
    getPropExamplesMap?: <TProp extends keyof TProps>(propName: TProp) => { [exampleName: string] : PropExampleObject<TProp> }
}

export interface DemoContext<TProps> {
    context: React.ComponentType<TProps>;
    name: string;
}

export interface IPropSamplesCreationContext<TProps = PropDocPropsUnknown> {
    getChangeHandler(name: string): (newValue: unknown) => void;
    getSelectedProps(): TProps;
    demoApi: IDemoApi;
    forceUpdate: () => void;
}

export type PropExampleObject<TProp> = {
    id?: string;
    name?: string;
    value: TProp;
    isDefault?: boolean;
};

export type PropExample<TProp> = PropExampleObject<TProp> | TProp;

export interface IPropDocEditor<TProp> {
    name: string;
    value: TProp;
    exampleId: string | undefined;
    examples: PropExampleObject<TProp>[];
    onValueChange(newValue: TProp): void;
    onExampleIdChange(newExampleId: string | undefined): void;
}

export type TSharedPropEditorType =
    'CssClassEditor' |
    'JsonEditor' |
    'JsonView' |
    'LinkEditor' |
    'NumEditor' |
    'StringEditor' |
    'StringWithExamplesEditor' |
    'MultiUnknownEditor' |
    'SingleUnknownEditor' |
    'IconEditor' |
    'CantResolve'
    ;

export type TPropDocEditorType = React.FC<IPropDocEditor<any>> | TSharedPropEditorType;

export interface PropDoc<TProps, TProp extends keyof TProps> {
    name: Extract<keyof TProps, string>;
    description?: string;
    isRequired: boolean;
    defaultValue?: TProps[TProp];
    examples?: PropExample<TProps[TProp]>[] | ((ctx: IPropSamplesCreationContext<TProps>) => PropExample<TProps[TProp]>[]);
    editorType?: TPropDocEditorType;
    remountOnChange?: boolean;
}

export type PropDocPropsUnknown = Record<string, unknown>;
export type PropDocUnknown = PropDoc<PropDocPropsUnknown, string>;

export enum TSkin {
    UUI = 'uui',
    Electric = 'electric',
    Loveship = 'loveship',
    Promo = 'promo'
}

export enum TDocContext {
    Default = 'Default',
    Block = 'Block',
    FlexRow = 'FlexRow',
    Form = 'Form',
    PagePanel = 'PagePanel',
    RelativePanel = 'RelativePanel',
    Resizable = 'Resizable',
    TabButton = 'TabButton',
    Table = 'Table',
    VerticalTabButton = 'VerticalTabButton',
    OpenedPickerBody = 'OpenedPickerBody'
}

export type TDocsGenExportedType = Autogenerated_TDocsGenExportedTypeRef;

export type IconBase<TIcon> = {
    id: string;
    icon: TIcon;
    name: string;
    path: string;
};

/**
 * Include prop in current "iteration" only when condition is met.
 * It is based on the values of parent props and current prop value which is going to be iterated.
 */
export type TPreviewPropsItemMatrixCondition<TProps> =
    (parentProps: TProps, thisPropValue?: unknown) => boolean;

type TPreviewPropsItemMatrixValues<TProps, TProp extends keyof TProps> = {
    /** Array of values to be directly passed to the component */
    values: TProps[TProp][];
    /**
     * exclude prop from current iteration based on the values of other props which are part of the same iteration
     */
    condition?: TPreviewPropsItemMatrixCondition<TProps>;
    examples?: never;
};
type TPreviewPropsItemMatrixExamples<TProps> = {
    /**
     * Array of example names or just a "*" which means all examples.
     * NOTE: it is NOT array of example ids, because ids are numeric and thus difficult to maintain.
     */
    examples: string[] | '*';
    /**
     * exclude prop from current iteration based on the values of other props which are part of the same iteration
     */
    condition?: TPreviewPropsItemMatrixCondition<TProps>;
    values?: never;
};

type TCellSize =
    // step=5 (until 200)
    | 20 | 25 | 30 | 35 | 40 | 45 | 50
    | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100
    | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150
    | 155 | 160 | 165 | 170 | 175 | 180 | 185 | 190 | 195 | 200
    // step=10 (until 500)
    | 210 | 220 | 230 | 240 | 250 | 260 | 270 | 280 | 290 | 300
    | 310 | 320 | 330 | 340 | 350 | 360 | 370 | 380 | 390 | 400
    | 410 | 420 | 430 | 440 | 450 | 460 | 470 | 480 | 490 | 500
    // etc.
    | 600 | 640 | 768 | 1280;
/**
 * Cell 'width-height'. E.g.: `100-200` (means 100px width and 200px height)
 *
 * Each "render case" is displayed inside a preview cell. This is cell size.
 *
 * The total width is fixed to 1280px.
 * The total height is dynamic and depends on total amount of cells and the cell size.
 */
export type TPreviewCellSize = `${TCellSize}-${TCellSize}`;

export type TPreviewPropsItemRenderCases = {
    id: string;
    context: TDocContext | undefined;
    cellSize: TPreviewCellSize | undefined;
    props: Record<string, unknown>[];
    matrix: TNormalizedMatrix[];
};
export type TNormalizedMatrix = Record<string, { values: unknown[]; condition?: TPreviewPropsItemMatrixCondition<any> } >;

export type TPreviewMatrix<T> = TComponentPreview<T>['matrix'];
export type TComponentPreview<TProps, TProp extends keyof TProps = keyof TProps> = {
    /** Optional group ID. It will visually group list of previews in the Property Explorer. */
    groupId?: string;
    /** A unique ID of the preview props which can be referenced by test automation */
    id: string;
    /**  TDocContext.Default will be used is nothing is passed */
    context?: TDocContext;
    /**
     * A map of prop names to prop values/examples.
     * The component will be repeated more than once in order to render all possible combinations: all-props/all-values/all-examples.
     */
    matrix: { [prop in TProp]?: TPreviewPropsItemMatrixValues<TProps, prop> | TPreviewPropsItemMatrixExamples<TProps> }
    | { [prop in TProp]?: TPreviewPropsItemMatrixValues<TProps, prop> | TPreviewPropsItemMatrixExamples<TProps> }[],
    /**
     * 'width-height'
     */
    cellSize?: TPreviewCellSize | undefined;
};
export type TComponentPreviewList<TProps> = TComponentPreview<TProps>[];
