import type { FC } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { GlyphIcon } from '@theorchard/suite-icons';
import { STORE } from '../../constants';
import { formatMessage } from '../../locale';
import { makeCancelable } from '../../utils/cancelablePromise';
import { formattedMessage } from '../../utils/i18Formatter';
import noop from '../../utils/noop';
import ArtistProfileLoader from '../artistPopover/artistProfileLoader';
import ArtistProfilesList from './artistProfilesList';
import ArtistProfilesPagination from './artistProfilesPagination';
import type { PageContext, ValidationContext } from './types';
import type { ArtistStoreProfile } from '../../types';
import type { CancelablePromise } from '../../utils/cancelablePromise';

const CLASS_NAME = 'AddNewArtist';

export interface Props {
    artist: string;
    onDone?: (context: ValidationContext) => void;
    onClose?: () => void;
    onFetch?: (artist: string) => Promise<PageContext[]>;
    onFetchMoreArtist?: (
        artist: string,
        limit: number,
        offset: number,
        store: number
    ) => Promise<ArtistStoreProfile[]>;
    onSelect?: (value: { id: string; profile: ArtistStoreProfile | null }) => void;
    loadingProfiles?: number;
    isCreate: boolean;
    isAnalyticsMode?: boolean;
}

const AddNewArtist: FC<Props> = ({
    artist,
    onDone,
    onClose,
    onFetch,
    onFetchMoreArtist,
    onSelect,
    loadingProfiles = 3,
    isCreate,
    isAnalyticsMode,
}) => {
    const [isLoading, setIsLoading] = useState(false);
    const [pagesContext, setPagesContext] = useState<PageContext[]>([]);

    useEffect(() => {
        let cancelableFetch: CancelablePromise<PageContext[]>;
        if (onFetch) {
            setIsLoading(true);
            cancelableFetch = makeCancelable(onFetch(artist));
            cancelableFetch.promise
                .then((value) => {
                    setPagesContext(value);
                    setIsLoading(false);
                })
                .catch(noop);
        }
        return () => {
            if (cancelableFetch) cancelableFetch.cancel();
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    const renderTabTitle = (store: number) => {
        const storeName = formatMessage(
            store === STORE.SPOTIFY ? 'addNewArtist.textSpotify' : 'addNewArtist.textApple'
        );
        let message;
        if (isCreate)
            message = formatMessage('addNewArtist.createTabTitle', {
                storeName,
            });
        else
            message = formatMessage('addNewArtist.updateTabTitle', {
                storeName,
            });

        const boldClass = `${CLASS_NAME}-content-tab-title-store-name`;
        return formattedMessage(message, (text, key) => (
            <span key={key} className={boldClass}>
                {text}
            </span>
        ));
    };
    const validationCallback = useCallback(
        ({ selectedProfile }: { selectedProfile?: ArtistStoreProfile | null }) =>
            selectedProfile !== undefined,
        []
    );

    const onFetchMore = async (store: number) => {
        if (!onFetchMoreArtist) return await Promise.resolve();

        const limit = 10;
        const currentPageContext = pagesContext.find((pageContext) => pageContext.store === store);
        const offset = currentPageContext?.data?.length ?? 0;

        return await onFetchMoreArtist(artist, limit, offset, store)
            .then((artists) => {
                if (!artists?.length) {
                    const updatedPagesContext = pagesContext.map((pageContext) => {
                        if (pageContext.store === store)
                            return { ...pageContext, hasMoreResult: false };
                        return { ...pageContext };
                    });
                    setPagesContext(updatedPagesContext);
                } else if (artists.length < limit) {
                    const updatedPagesContext: PageContext[] = pagesContext.map((pageContext) => {
                        if (pageContext.store === store)
                            return {
                                ...pageContext,
                                data: [...pageContext.data, ...artists],
                                hasMoreResult: false,
                            };
                        return { ...pageContext };
                    });
                    setPagesContext(updatedPagesContext);
                } else {
                    const updatedPagesContext = pagesContext.map((pageContext) => {
                        if (pageContext.store === store)
                            return {
                                ...pageContext,
                                data: [...pageContext.data, ...artists],
                                hasMoreResult: true,
                            };
                        return { ...pageContext };
                    });
                    setPagesContext(updatedPagesContext);
                }
            })
            .catch(noop);
    };

    const onFetchAppleProfile = async (name: string) => {
        if (!onFetchMoreArtist) return await Promise.resolve();

        const limit = 25;
        const offset = 0;
        const store = 1;
        return await onFetchMoreArtist(name, limit, offset, store)
            .then((artists) => {
                if (!artists?.length || artists.length < limit) {
                    const updatedPagesContext = pagesContext.map((pageContext) => {
                        if (pageContext.store === store)
                            return {
                                ...pageContext,
                                data: artists,
                                hasMoreResult: false,
                            };
                        return { ...pageContext };
                    });
                    setPagesContext(updatedPagesContext);
                } else {
                    const updatedPagesContext = pagesContext.map((pageContext) => {
                        if (pageContext.store === store)
                            return {
                                ...pageContext,
                                data: artists,
                                hasMoreResult: true,
                            };
                        return { ...pageContext };
                    });
                    setPagesContext(updatedPagesContext);
                }
            })
            .catch(noop);
    };

    const renderContent = () => {
        const loadingSlots = [...Array(loadingProfiles).keys()];
        if (isLoading)
            return (
                <div className={`${CLASS_NAME}-loading`}>
                    {loadingSlots.map((key) => (
                        <ArtistProfileLoader key={key} />
                    ))}
                </div>
            );
        return (
            <div className={`${CLASS_NAME}-content`}>
                <ArtistProfilesPagination
                    pagesContext={pagesContext}
                    backText={formatMessage('addNewArtist.back')}
                    doneText={formatMessage('addNewArtist.done')}
                    nextText={formatMessage('addNewArtist.next')}
                    onDone={onDone}
                    onValidate={validationCallback}
                    isCreate={isCreate}
                    isAnalyticsMode={isAnalyticsMode}
                    onNext={onFetchAppleProfile}
                >
                    {({ tabId, store, data, hasMoreResult }, { onValidate, isVisible }) => (
                        <ArtistProfilesList
                            id={tabId}
                            key={store}
                            store={store}
                            titleContent={renderTabTitle(store)}
                            emptyProfileContent={
                                <div className={`${CLASS_NAME}-content-empty`}>
                                    {formatMessage(
                                        store === STORE.SPOTIFY
                                            ? 'addNewArtist.emptySpotify'
                                            : 'addNewArtist.emptyApple'
                                    )}
                                </div>
                            }
                            profiles={data}
                            isVisible={isVisible}
                            onValidate={onValidate}
                            onChange={onSelect}
                            isAnalyticsMode={isAnalyticsMode}
                            onFetchMore={onFetchMore}
                            hasMoreResult={hasMoreResult}
                        />
                    )}
                </ArtistProfilesPagination>
            </div>
        );
    };
    return (
        <div className={CLASS_NAME}>
            <div className={`${CLASS_NAME}-header`}>
                <div className={`${CLASS_NAME}-header-caption`}>
                    {formatMessage(
                        isCreate ? 'addNewArtist.createTitle' : 'addNewArtist.updateTitle'
                    )}
                </div>
                <div
                    role="button"
                    tabIndex={0}
                    className={`${CLASS_NAME}-header-close`}
                    onClick={onClose}
                    onKeyDown={onClose}
                >
                    <GlyphIcon name="close" size={16} />
                </div>
            </div>
            {renderContent()}
        </div>
    );
};

export default AddNewArtist;
