import React, { PureComponent } from 'react';
import { Button } from '@theorchard/suite-components';
import { GlyphIcon } from '@theorchard/suite-icons';
import cx from 'classnames';
import { get } from 'lodash-es';
import { trackSegmentEvent } from '../../../utils/analytics';
import type { ArtistProfile, ValidationContext } from '../types';

const CLASS_NAME = 'ArtistProfilesPagination';

export type OnValidateCallback<V> = (
    context: V,
    validationContext: ValidationContext<V> | null
) => [boolean, object] | boolean;

export type OnDoneCallback<V> = (context: ValidationContext<V>) => void;

export interface Props<T, V> {
    children?: (
        context: T,
        props: {
            isVisible: boolean;
            onValidate: (props: V) => void;
        }
    ) => JSX.Element;
    backText?: string;
    doneText?: string;
    isAnalyticsMode?: boolean;
    isCreate?: boolean;
    nextText?: string;
    onDone?: OnDoneCallback<V>;
    onNext?: (name: string) => Promise<void>;
    onValidate?: OnValidateCallback<V>;
    pagesContext: T[];
    selectedProfile?: ArtistProfile;
    showDotPages?: boolean;
}

interface State<V> {
    page: number;
    isPageValid: boolean;
    validationContext: ValidationContext<V>;
    lastSelectedProfileIsNull: boolean;
}

export default class ArtistProfilesPagination<T = object, V = object> extends PureComponent<
    Props<T, V>,
    State<V>
> {
    constructor(props: Props<T, V>) {
        super(props);
        this.state = {
            page: 0,
            isPageValid: true,
            validationContext: {},
            lastSelectedProfileIsNull: false,
        };
    }

    handleSetPage = (page: number) => {
        const { pagesContext } = this.props;
        const { page: currentPage, isPageValid } = this.state;
        const normalizedPage = Math.max(Math.min(page, pagesContext.length - 1), 0);
        const isPageLessThanCurrent = normalizedPage <= currentPage;
        if (isPageValid || isPageLessThanCurrent) this.setState({ page: normalizedPage });
    };

    handleBack = () => {
        const { page } = this.state;
        this.handleSetPage(page - 1);
    };

    handleNext = () => {
        const { pagesContext, isCreate, isAnalyticsMode, onNext } = this.props;
        const { page, lastSelectedProfileIsNull, validationContext } = this.state;
        if (lastSelectedProfileIsNull) {
            const context = pagesContext[page];
            const store = get(context, 'store');

            if (isAnalyticsMode)
                trackSegmentEvent({
                    name: isCreate ? 'create new participant' : 'update participant',
                    properties: {
                        category: 'DPB Basics Page',
                        label:
                            store === 1
                                ? `not found - Apple (${store})`
                                : `not found - Spotify (${store})`,
                        value: 1,
                    },
                });
            this.setState({ lastSelectedProfileIsNull: false });
            this.handleSetPage(page + 1);
            return;
        }

        if (!lastSelectedProfileIsNull && validationContext && onNext) {
            const { 0: pageContext } = validationContext;
            const name = get(pageContext, 'selectedProfile.name');
            void onNext(`${name}`).then(() => this.handleSetPage(page + 1));
        }
    };

    handleValidate = (updatedProps: V) => {
        const { onValidate } = this.props;
        const { page, validationContext: context } = this.state;
        const defaultContext = { ...context, [page]: updatedProps };

        if (!onValidate) {
            this.setState({ validationContext: defaultContext });
            return;
        }

        const lastSelectedProfileIsNull =
            updatedProps && get(updatedProps, 'selectedProfile') === null;
        this.setState({ lastSelectedProfileIsNull });

        const validateResult = onValidate(updatedProps, context);
        if (Array.isArray(validateResult)) {
            const [isPageValid, validationContext] = validateResult;
            const customContext = { ...context, ...validationContext };
            this.setState({ isPageValid, validationContext: customContext });
        } else
            this.setState({
                isPageValid: Boolean(validateResult),
                validationContext: defaultContext,
            });
    };

    handleDone = () => {
        const { onDone, pagesContext, isCreate, isAnalyticsMode } = this.props;
        const { validationContext, page, lastSelectedProfileIsNull } = this.state;

        this.setState({ isPageValid: false });

        if (lastSelectedProfileIsNull) {
            const context = pagesContext[page];
            const store = get(context, 'store');

            if (isAnalyticsMode)
                trackSegmentEvent({
                    name: isCreate ? 'create new participant' : 'update participant',
                    properties: {
                        category: 'DPB Basics Page',
                        label:
                            store === 1
                                ? `not found - Apple (${store})`
                                : `not found - Spotify (${store})`,
                        value: 1,
                    },
                });
            this.setState({ lastSelectedProfileIsNull: false });
        }
        if (onDone) onDone(validationContext);
    };

    renderBackButton() {
        const { backText } = this.props;
        const { page } = this.state;
        if (page === 0) return null;
        return (
            <Button variant="link" onClick={this.handleBack} className={`${CLASS_NAME}-back`}>
                <GlyphIcon name="caretLeft" size={12} />
                {backText}
            </Button>
        );
    }

    renderNextDoneButton() {
        const { nextText, doneText, pagesContext } = this.props;
        const { page, isPageValid } = this.state;
        const commonProps = { variant: 'primary', disabled: !isPageValid };
        if (page === pagesContext.length - 1)
            return (
                <Button onClick={this.handleDone} className={`${CLASS_NAME}-done`} {...commonProps}>
                    {doneText}
                </Button>
            );
        return (
            <Button onClick={this.handleNext} className={`${CLASS_NAME}-next`} {...commonProps}>
                {nextText}
                <GlyphIcon name="caretRight" size={12} />
            </Button>
        );
    }

    renderPages() {
        const { pagesContext, showDotPages } = this.props;
        const { page } = this.state;
        if (!showDotPages || pagesContext.length < 2) return null;
        return [...Array(pagesContext.length).keys()].map((key) => {
            const pageIconClass = cx(`${CLASS_NAME}-page-icon`, {
                [`${CLASS_NAME}-page-icon-active`]: key === page,
            });
            return (
                <li key={key} className={`${CLASS_NAME}-page-button`}>
                    <div className={pageIconClass} />
                </li>
            );
        });
    }

    renderContent() {
        const { pagesContext, children } = this.props;
        const { page } = this.state;
        return (
            <div className={`${CLASS_NAME}-content`}>
                {pagesContext.map((context, index) =>
                    children?.(context, {
                        isVisible: index === page,
                        onValidate: this.handleValidate,
                    })
                )}
            </div>
        );
    }

    render() {
        const { pagesContext } = this.props;
        if (!pagesContext.length) return null;
        return (
            <div className={CLASS_NAME}>
                {this.renderContent()}
                <div className={`${CLASS_NAME}-footer`}>
                    <div className={`${CLASS_NAME}-footer-left`}>{this.renderBackButton()}</div>
                    <ul className={`${CLASS_NAME}-buttons`}>{this.renderPages()}</ul>
                    <div className={`${CLASS_NAME}-footer-right`}>
                        {this.renderNextDoneButton()}
                    </div>
                </div>
            </div>
        );
    }
}
