/**
 * The navigation bar at the steps for the Wizard
 * Represents a chain of wizard steps with the ability to switch to any available steps
 * Works with Wizardcontent for easy access to the state and methods of the wizard
 * You need to connect this component inside the Step where navigation is required
 *
 * @author: Denis Makarov
 * @date: 2020-02-12
 */

import * as React from 'react';
import keyBy from 'lodash/keyBy';
import {WizardContext} from '../Wizard';
import {StepSchema, WizardContextProps, WizardStep} from '../../../type/WizardTypes';
import {Steps} from 'antd';
import {IStringKeyMap} from '../../../type';
import * as styles from './navigation.m.scss';

type StepSize = 'default' | 'small';

interface IProps {
    allowPrev?: boolean;
    allowNext?: boolean;
    beforePrevStep?: () => void;
    beforeNextStep?: () => void;
    stepSize?: StepSize;
}

interface IDefaultProps {
    allowPrev: boolean;
    allowNext: boolean;
    stepSize: StepSize;
}

const {Step} = Steps;

export class Navigation extends React.Component<IProps> {
    static defaultProps: IDefaultProps = {
        allowPrev: true,
        allowNext: true,
        stepSize: 'small'
    };

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

        this.moveToStep = this.moveToStep.bind(this);
    }

    moveToStep (wizardProps: WizardContextProps,
                nextStepKey: string,
                nextStepAllowed: boolean,
                nextStepIndex: number,
                activeStepIndex: number) {

        const moveNext = nextStepIndex > activeStepIndex;

        if (!nextStepAllowed) {
            return;
        }

        if (moveNext && this.props.beforeNextStep) {
            this.props.beforeNextStep();

            return;
        }

        if (!moveNext && this.props.beforePrevStep) {
            this.props.beforePrevStep();

            return;
        }

        wizardProps.moveToStep(nextStepKey);
    }


    private isStepAllowed (currentStepIndex: number, index: number) {
        let stepAllowed = false;

        if (currentStepIndex + 1 === index && this.props.allowNext) { // next step
            stepAllowed = true;
        } else if (currentStepIndex > index) { // prev steps
            stepAllowed = true;
        }

        return stepAllowed;
    }

    private static buildStepsChain (currentStepName: string, steps: WizardStep[], stepsSchema?: IStringKeyMap<StepSchema>) {
        let array: WizardStep [];

        if (!stepsSchema) {
            array = steps;

            return array;
        }

        return Navigation.buildStepsChainFromSchema(currentStepName, steps, stepsSchema);
    }

    private static buildStepsChainFromSchema (currentStep: string, steps: WizardStep [], stepsSchema: IStringKeyMap<StepSchema>) {
        const stepsMap = keyBy(steps, 'name');
        const array: WizardStep [] = [];

        array.push(stepsMap[currentStep]);

        const currentSchemaStep: StepSchema = stepsSchema[currentStep];

        let prevStep = currentSchemaStep.prev;
        let nextStep = currentSchemaStep.next;

        while (prevStep) {
            array.unshift(stepsMap[prevStep]); // insert the previous steps at the beginning

            prevStep = stepsSchema[prevStep].prev;
        }

        while (nextStep) {
            array.push(stepsMap[nextStep]); // the next steps are inserted at the end

            nextStep = stepsSchema[nextStep].next;
        }

        return array;
    }

    override render () {
        return (
            <WizardContext.Consumer>
                {(wizardProps: WizardContextProps) => {
                    const stepsChain = Navigation.buildStepsChain(wizardProps.currentStep, wizardProps.steps, wizardProps.stepsSchema);
                    const currentStepIndex = stepsChain.findIndex((step: WizardStep) => step.name === wizardProps.currentStep);

                    return (
                        <div className={styles.navigationContainer}>
                            <Steps
                                labelPlacement={'vertical'}
                                className={styles.navigation}
                                size={this.props.stepSize}
                                current={currentStepIndex}
                            >
                                {stepsChain.map((step: WizardStep, index: number) => {
                                    const stepAllowed = this.isStepAllowed(currentStepIndex, index);

                                    return (
                                        <Step
                                            disabled={!stepAllowed}
                                            title={step.label}
                                            onClick={this.moveToStep.bind(
                                                this,
                                                wizardProps,
                                                step.name,
                                                stepAllowed,
                                                index,
                                                currentStepIndex
                                            )}
                                            key={step.name}>
                                        </Step>
);
                                })}
                            </Steps>
                        </div>
);
                }}
            </WizardContext.Consumer>
        );
    }
}
