import { Alert, Button } from '@theorchard/suite-components';
import React, { useEffect, useState } from 'react';
import OAPanel from 'shared/components/oaPanel';
import { MarketingHighlightStore } from 'shared/data/schema';
import { PriorityIdType } from 'src/types';
import MarketingDetails from './marketingDetails';
import type { FC } from 'react';
import type {
    GraphQLState,
    MarketingHighlight,
    MarketingHighlightsState,
    MarketingPriorityInternalNote,
    MarketingPriorityState,
    MarketingProgramInfo,
    MarketingProgramInfosState,
    MarketingProgramInfoUpdateResult,
    ProductMarketingPriorityUpdateResult,
    ProjectMarketingPriorityUpdateResult,
    TerritoryMap,
    TerritoryMarketingPriority,
} from 'src/types';

export interface MarketingSectionOAPanelProps {
    productId: string;
    graphqlState: GraphQLState;
    updateProductInternalNote: (value: string) => Promise<any>;
    updateProductMarketingPriorities: (
        value: TerritoryMarketingPriority[]
    ) => Promise<ProductMarketingPriorityUpdateResult>;
    updateProductMarketingProgramInfo: (
        value: MarketingProgramInfo[]
    ) => Promise<MarketingProgramInfoUpdateResult>;
    updateProjectMarketingPriorities: (
        value: TerritoryMarketingPriority[]
    ) => Promise<ProjectMarketingPriorityUpdateResult>;
    updateProjectMarketingHighlights: (
        value: MarketingHighlight[]
    ) => Promise<any>;
    toast: (value: string) => void;
    loading: boolean;
    editable: boolean;
    error: boolean;
    debug?: boolean;
    onEdit: () => void;
}

export const MarketingSectionOAPanel: FC<MarketingSectionOAPanelProps> = ({
    productId,
    graphqlState,
    updateProductInternalNote,
    updateProductMarketingPriorities,
    updateProductMarketingProgramInfo,
    updateProjectMarketingPriorities,
    updateProjectMarketingHighlights,
    toast,
    loading,
    editable,
    error,
    debug = false,
    onEdit,
}) => {
    const className = 'MarketingSectionOAPanel';
    const i18nPrefix = 'marketingSection.marketingSectionOaPanel';

    const appleStore = MarketingHighlightStore.MARKETING_HIGHLIGHTS_STORE_APPLE;
    const spotifyStore =
        MarketingHighlightStore.MARKETING_HIGHLIGHTS_STORE_SPOTIFY;

    const [
        isMarketingHighlightsUpdated,
        setIsProjectMarketingHighlightsUpdated,
    ] = useState<boolean>(false);
    const [isMarketingProgramInfoUpdated, setIsMarketingProgramInfoUpdated] =
        useState<boolean>(false);
    const [isMarketingPriorityUpdated, setIsMarketingPriorityUpdated] =
        useState<boolean>(false);
    const [isInternalNoteUpdated, setIsInternalNoteUpdated] =
        useState<boolean>(false);

    const {
        project: graphqlProject,
        product: graphqlProduct,
        territories: marketingTerritories,
    } = graphqlState;

    const [projectProductCount, setProjectProductCount] = useState<number>(
        graphqlProject?.productCount ?? 1
    );
    useEffect(() => {
        graphqlProject &&
            graphqlProject.productCount &&
            graphqlProject.productCount > 0 &&
            setProjectProductCount(graphqlProject.productCount);
    }, [graphqlProject?.productCount]);

    const [isProjectLevel, setProjectLevel] = useState<boolean | null>(() => {
        const hasProjectPriorities =
            !!graphqlProject?.marketingPriority?.priorities?.length;
        const hasProductPriorities =
            !!graphqlProduct?.marketingPriority?.priorities?.length;

        if (!hasProjectPriorities && !hasProductPriorities) {
            return null;
        }

        return hasProductPriorities;
    });
    const [internalNote, setInternalNote] = useState<string>(
        graphqlProduct?.marketingPriority?.internalNote ?? ''
    );

    const [marketingTerritoriesMap, setMarketingTerritoriesMap] =
        useState<TerritoryMap>(
            Object.fromEntries(
                marketingTerritories?.map(item => [item.countryId, item]) ?? []
            )
        );
    useEffect(() => {
        marketingTerritories &&
            marketingTerritories.length > 0 &&
            setMarketingTerritoriesMap(
                Object.fromEntries(
                    marketingTerritories.map(item => [item.countryId, item])
                )
            );
    }, [JSON.stringify(marketingTerritories)]);

    const setMarketingPriorityDefault = () => {
        const marketingPriority = isProjectLevel
            ? graphqlProject?.marketingPriority
            : graphqlProduct?.marketingPriority;
        const idType = isProjectLevel
            ? PriorityIdType.Project
            : PriorityIdType.Product;

        if (Object.keys(marketingTerritoriesMap).length === 0) {
            return [];
        }

        return (
            marketingPriority?.priorities?.map(pri => ({
                ...pri,
                ...marketingTerritoriesMap[pri.territoryId],
                priorityIdType: pri.priorityId ? idType : undefined,
            })) ?? []
        );
    };
    const [marketingPriority, setMarketingPriority] = useState<
        TerritoryMarketingPriority[]
    >(setMarketingPriorityDefault());

    const modifyProjectLevel = (value: boolean | null) => {
        setIsMarketingPriorityUpdated(true);
        setProjectLevel(value);
    };
    const modifyMarketingPriority = (value: TerritoryMarketingPriority[]) => {
        setIsMarketingPriorityUpdated(true);
        setMarketingPriority(value);
    };
    const modifyInternalNote = (value: string) => {
        setIsInternalNoteUpdated(true);
        setInternalNote(value);
    };

    const marketingPriorityState = {
        projectProductCount,
        isProjectLevel,
        internalNote,
        marketingPriority,
        setProjectLevel: modifyProjectLevel,
        setInternalNote: modifyInternalNote,
        setMarketingPriority: modifyMarketingPriority,
    };

    const [projectMarketingHighlights, setProjectMarketingHighlights] =
        useState<MarketingHighlight[]>([
            {
                marketingHighlight:
                    graphqlProject?.marketingHighlights?.find(
                        e => !e.store && !e.countryId
                    )?.marketingHighlight ||
                    (editable
                        ? $t(`${i18nPrefix}.globalMktHighlightsTemplate`)
                        : ''),
            },
            {
                store: appleStore,
                marketingHighlight:
                    graphqlProject?.marketingHighlights?.find(
                        e => e.store === appleStore
                    )?.marketingHighlight ?? '',
            },
            {
                store: spotifyStore,
                marketingHighlight:
                    graphqlProject?.marketingHighlights?.find(
                        e => e.store === spotifyStore
                    )?.marketingHighlight ?? '',
            },
            ...(graphqlProject?.marketingHighlights?.filter(e => e.countryId) ||
                []),
        ]);

    const modifyProjectMarketingHighlights = (value: MarketingHighlight[]) => {
        setIsProjectMarketingHighlightsUpdated(true);
        setProjectMarketingHighlights(value);
    };

    const marketingHighlightsState = {
        projectMarketingHighlights,
        setProjectMarketingHighlights: modifyProjectMarketingHighlights,
    };

    const [marketingProgramInfos, setMarketingProgramInfos] = useState<
        MarketingProgramInfo[]
    >(graphqlProduct?.marketingProgramInfos ?? []);

    const modifyMarketingProgramInfos = (value: MarketingProgramInfo[]) => {
        setIsMarketingProgramInfoUpdated(true);
        setMarketingProgramInfos(value);
    };

    const marketingProgramInfosState = {
        marketingProgramInfos,
        setMarketingProgramInfos: modifyMarketingProgramInfos,
    };

    useEffect(() => {
        graphqlProject?.marketingHighlights &&
            graphqlProject?.marketingHighlights.length > 0 &&
            setProjectMarketingHighlights([
                {
                    marketingHighlight:
                        graphqlProject?.marketingHighlights?.find(
                            e => !e.store && !e.countryId
                        )?.marketingHighlight ||
                        (editable
                            ? $t(`${i18nPrefix}.globalMktHighlightsTemplate`)
                            : ''),
                },
                {
                    store: appleStore,
                    marketingHighlight:
                        graphqlProject?.marketingHighlights?.find(
                            e => e.store === appleStore
                        )?.marketingHighlight ?? '',
                },
                {
                    store: spotifyStore,
                    marketingHighlight:
                        graphqlProject?.marketingHighlights?.find(
                            e => e.store === spotifyStore
                        )?.marketingHighlight ?? '',
                },
                ...(graphqlProject?.marketingHighlights?.filter(
                    e => e.countryId
                ) || []),
            ]);
    }, [JSON.stringify(graphqlProject?.marketingHighlights)]);

    useEffect(() => {
        graphqlProduct?.marketingProgramInfos &&
            graphqlProduct?.marketingProgramInfos?.length > 0 &&
            setMarketingProgramInfos(graphqlProduct.marketingProgramInfos);
    }, [JSON.stringify(graphqlProduct?.marketingProgramInfos)]);

    const setProjectLevelIfDefined = (
        marketingPriority: MarketingPriorityInternalNote,
        projectLevel: boolean
    ) =>
        marketingPriority &&
        marketingPriority.priorities &&
        marketingPriority.priorities.length > 0 &&
        setProjectLevel(projectLevel);

    const setMarketingPriorityIfDefined = (
        marketingTerritoriesMap: TerritoryMap,
        marketingPriority: MarketingPriorityInternalNote,
        idType: PriorityIdType
    ) =>
        Object.keys(marketingTerritoriesMap).length > 0 &&
        marketingPriority &&
        marketingPriority.priorities &&
        marketingPriority.priorities.length > 0 &&
        setMarketingPriority(
            marketingPriority.priorities.map(pri => ({
                ...pri,
                ...marketingTerritoriesMap[pri.territoryId],
                priorityIdType: pri.priorityId ? idType : undefined,
            })) ?? []
        );

    const setInternalNoteIfDefined = (
        marketingPriority: MarketingPriorityInternalNote
    ) =>
        marketingPriority &&
        marketingPriority.internalNote &&
        setInternalNote(marketingPriority.internalNote);

    useEffect(() => {
        setProjectLevelIfDefined(graphqlProject?.marketingPriority, true);
        setMarketingPriorityIfDefined(
            marketingTerritoriesMap,
            graphqlProject?.marketingPriority,
            PriorityIdType.Project
        );
    }, [graphqlProject?.marketingPriority, marketingTerritoriesMap]);

    useEffect(() => {
        setProjectLevelIfDefined(graphqlProduct?.marketingPriority, false);
        setMarketingPriorityIfDefined(
            marketingTerritoriesMap,
            graphqlProduct?.marketingPriority,
            PriorityIdType.Product
        );
        setInternalNoteIfDefined(graphqlProduct?.marketingPriority);
    }, [graphqlProduct?.marketingPriority, marketingTerritoriesMap]);

    useEffect(() => {
        if (
            isMarketingHighlightsUpdated ||
            isMarketingProgramInfoUpdated ||
            isMarketingPriorityUpdated ||
            isInternalNoteUpdated
        ) {
            window.onbeforeunload = () => true;
        }

        return () => {
            window.onbeforeunload = null;
        };
    }, [
        isMarketingHighlightsUpdated ||
            isMarketingProgramInfoUpdated ||
            isMarketingPriorityUpdated ||
            isInternalNoteUpdated,
    ]);

    const toastMessage = (isProjectLevel: boolean | null) => {
        const toastParams = {
            level: isProjectLevel
                ? $t(`${i18nPrefix}.project`)
                : $t(`${i18nPrefix}.product`),
        };
        if (isProjectLevel === null)
            return $t(`${i18nPrefix}.updateSkipSuccess`);
        else if (marketingPriority.length > 0)
            return $t(`${i18nPrefix}.updateSuccess`, toastParams);
        else return $t(`${i18nPrefix}.updateClearSuccess`, toastParams);
    };

    const submit = async (
        marketingPriorityState: MarketingPriorityState,
        marketingHighlightsState: MarketingHighlightsState,
        marketingProgramInfosState: MarketingProgramInfosState
    ) => {
        const { projectMarketingHighlights } = marketingHighlightsState;
        let projectMarketingHighlightsUpdate = null;
        if (isMarketingHighlightsUpdated)
            projectMarketingHighlightsUpdate = updateProjectMarketingHighlights(
                projectMarketingHighlights
            );

        const { marketingProgramInfos, setMarketingProgramInfos } =
            marketingProgramInfosState;
        let productMarketingProgramInfoUpdate = null;
        if (isMarketingProgramInfoUpdated)
            productMarketingProgramInfoUpdate =
                updateProductMarketingProgramInfo(marketingProgramInfos).then(
                    result =>
                        setMarketingProgramInfos(
                            result.data.upsertMarketingProgramInfo
                        )
                );

        const {
            isProjectLevel,
            internalNote,
            marketingPriority,
            setProjectLevel,
            setMarketingPriority,
        } = marketingPriorityState;

        let internalNoteUpdate = null;
        if (isInternalNoteUpdated)
            internalNoteUpdate = updateProductInternalNote(internalNote);

        let marketingPrioritiesUpdate = null;
        if (isMarketingPriorityUpdated && isProjectLevel !== null) {
            marketingPrioritiesUpdate = isProjectLevel
                ? updateProjectMarketingPriorities(marketingPriority)
                : updateProductMarketingPriorities(marketingPriority);

            marketingPrioritiesUpdate.then(result => {
                let updateData: TerritoryMarketingPriority[] = [];

                if (isProjectLevel)
                    updateData = (
                        result as ProjectMarketingPriorityUpdateResult
                    ).data.updateProjectMarketingPriorities;
                else
                    updateData = (
                        result as ProductMarketingPriorityUpdateResult
                    ).data.updateProductMarketingPriorities;

                const idType = isProjectLevel
                    ? PriorityIdType.Project
                    : PriorityIdType.Product;

                setMarketingPriority(
                    updateData.map(pri => ({
                        ...pri,
                        ...marketingTerritoriesMap[pri.territoryId],
                        priorityIdType: pri.priorityId ? idType : undefined,
                    })) ?? []
                );
            });
        }

        await Promise.all([
            internalNoteUpdate,
            projectMarketingHighlightsUpdate,
            productMarketingProgramInfoUpdate,
            marketingPrioritiesUpdate,
        ]);

        toast(toastMessage(isProjectLevel));

        if (marketingPriority.length === 0) setProjectLevel(null);

        setIsProjectMarketingHighlightsUpdated(false);
        setIsMarketingProgramInfoUpdated(false);
        setIsMarketingPriorityUpdated(false);
        setIsInternalNoteUpdated(false);
    };

    const footer = (
        <div className={`${className}-footer`}>
            <div className={`${className}-footer-warning`}>
                {isProjectLevel === null && marketingPriority.length > 0 && (
                    <Alert
                        className={`${className}-footer-level-warning`}
                        variant="warn"
                        text={$t(`${i18nPrefix}.footerWarningLevel`)}
                    />
                )}
                {isProjectLevel !== null && marketingPriority.length === 0 && (
                    <Alert
                        className={`${className}-footer-territory-warning`}
                        variant="warn"
                        text={$t(`${i18nPrefix}.footerWarningTerritory`)}
                    />
                )}
            </div>
            {editable && (
                <div className={`${className}-footer-button`}>
                    <Button
                        disabled={false}
                        data-testid="submit-button"
                        variant="primary"
                        onClick={() =>
                            submit(
                                marketingPriorityState,
                                marketingHighlightsState,
                                marketingProgramInfosState
                            )
                        }
                    >
                        {$t(`${i18nPrefix}.submit`)}
                    </Button>
                </div>
            )}
        </div>
    );

    return (
        <OAPanel
            title={$t(`${i18nPrefix}.header`)}
            editable={editable}
            debug={debug}
            onEdit={onEdit}
            loading={loading}
            error={error}
            footer={footer}
        >
            <MarketingDetails
                productId={productId}
                marketingPriorityState={marketingPriorityState}
                marketingHighlightsState={marketingHighlightsState}
                marketingProgramInfosState={marketingProgramInfosState}
                marketingTerritories={marketingTerritories}
                editable={editable}
                debug={debug}
                onEdit={onEdit}
            />
        </OAPanel>
    );
};

export default MarketingSectionOAPanel;
