/**
 * Wizard Component
 * Displays the passed components of steps
 * Can organize the display of steps according to the diagram, if it is passed
 * Copies the wizard's props to the step component for easy access to the wizard's state and methods
 *
 * Is a provider for components
 * @see {Navigation}
 * @see {Footer}
 *
 * @author: Denis Makarov
 * @date: 2020-02-12
 */

import * as React from 'react';
import {StepSchema, WizardContextProps, WizardStep} from '../../type/WizardTypes';
import {Content} from './content/Content';
import * as styles from './wizard.m.scss';
import {IStringKeyMap} from '../../type';
import {Navigation} from './navigation/Navigation';
import {Footer, IWizardFooterProps} from './footer/Footer';

export interface IWizardProps {
    steps: WizardStep[];
    firstStep?: string;
    stepsSchema?: IStringKeyMap<StepSchema>;
    onSubmit: () => void;
}

interface IState {
    activeStepKey: string;
}

export {
    IWizardFooterProps
};

export const WizardContext = React.createContext<WizardContextProps | null>(null);

export class Wizard extends React.Component<IWizardProps, IState> {
    static Footer = Footer;
    static Navigation = Navigation;
    static Content = Content;

    constructor (props: IWizardProps) {
        super(props);

        let firstStepKey = this.props.stepsSchema && this.props.firstStep;

        if (!firstStepKey) {
            firstStepKey = this.props.steps[0].name;
        }

        this.state = {
            activeStepKey: firstStepKey
        };
    }

    get activeStep () {
        return this.props.steps.find((el: WizardStep) => el.name === this.state.activeStepKey);
    }

    getNextStep () {
        if (this.props.stepsSchema) {
            return this.props.stepsSchema[this.state.activeStepKey].next;
        }

        const currentStep = this.activeStep;

        if (!currentStep) {
            return null;
        }

        const currentStepKey = currentStep.name;
        const currentStepIndex = this.props.steps.findIndex((step: WizardStep) => step.name === currentStepKey);
        const nextStep = this.props.steps[currentStepIndex + 1];

        return nextStep ? nextStep.name : null;
    }

    getPrevStep () {
        if (this.props.stepsSchema) {
            return this.props.stepsSchema[this.state.activeStepKey].prev;
        }

        const currentStep = this.activeStep;

        if (!currentStep) {
            return null;
        }

        const currentStepKey = currentStep.name;
        const currentStepIndex = this.props.steps.findIndex((step: WizardStep) => step.name === currentStepKey);
        const nextStep = this.props.steps[currentStepIndex - 1];

        return nextStep ? nextStep.name : null;
    }

    moveNextStep () {
        this.move(true);
    }


    movePrevStep () {
        this.move(false);
    }

    moveToStep (stepKey: string) {
        this.setState({activeStepKey: stepKey});
    }

    private move (moveNext: boolean) {
        const currentStep = this.activeStep;

        if (!currentStep) {
            return;
        }

        const currentStepKey = currentStep.name;

        let currentStepIndex = this.props.steps.findIndex((step: WizardStep) => step.name === currentStepKey);
        let nextStepKey: string | null = null;

        if (currentStepIndex < 0) {
            return;
        }

        if (this.props.stepsSchema) {
            nextStepKey = moveNext ? this.props.stepsSchema[currentStep.name].next : this.props.stepsSchema[currentStep.name].prev;
        } else {
            let stepToMove = moveNext ? this.props.steps[currentStepIndex + 1] : this.props.steps[currentStepIndex - 1];

            if (stepToMove) {
                nextStepKey = stepToMove.name;
            }
        }

        if (!nextStepKey) {
            return;
        }

        this.setState({activeStepKey: nextStepKey});
    }

    override render () {
        const step = this.props.steps.find((step: WizardStep) => step.name === this.state.activeStepKey);

        if (!step) {
            return null;
        }

        const StepComponent = step.component;

        const wizardProps: WizardContextProps = {
            moveToStep: this.moveToStep.bind(this),
            moveNextStep: this.moveNextStep.bind(this),
            movePrevStep: this.movePrevStep.bind(this),
            onSubmit: this.props.onSubmit,
            steps: this.props.steps,
            stepsSchema: this.props.stepsSchema,
            currentStep: this.state.activeStepKey,
            getNextStep: this.getNextStep.bind(this),
            getPrevStep: this.getPrevStep.bind(this)
        };

        return (
            <div className={styles.wizard}>
                <WizardContext.Provider value={wizardProps}>
                    {/*using clone to save ref to StepComponent*/}
                    {React.cloneElement(StepComponent, wizardProps)}
                </WizardContext.Provider>
            </div>
        );
    }


}
