import React from 'react';
import { Button, LoadingButton, Modal, ProductDisplayType, WarningGlyph } from '@orchard/frontend-react-components';
import { formatMessage } from '@orchard/frontend-localization';
import { renderConfigurationIcon } from 'src/utils/configuration-icon';
import { Split, LabelSoundRecordingTrack, LabelSoundRecordingSplit } from 'src/queries/product';
import { CreateCollaboratorSplitInput, DeleteCollaboratorSplitInput, UpdateCollaboratorSplitInput } from 'src/__definitions__/globalTypes';
import { SPLIT_TYPE_IDS } from 'src/constants';
import { useSaveCollaboratorSplitsMutation } from 'src/mutations/save-collaborator-splits';
import messages from './i18n';

const CLASS_NAME = 'BulkSplitsModal';

const getSaveCollaboratorSplitsVariables = (tracksWithSameIsrc: LabelSoundRecordingTrack[], trackSplits: Split[]) => {
    const splitsToCreate: CreateCollaboratorSplitInput[] = [];
    const splitsToUpdateWithIdentifiers: (UpdateCollaboratorSplitInput & {
        identifier: string;
    })[] = [];
    const splitsToDelete: DeleteCollaboratorSplitInput[] = [];

    if (tracksWithSameIsrc.length > 0) {
        const tracksWithExistingSplits = tracksWithSameIsrc.filter((track) => track.splits.length > 0);
        const trackSplitsByCollaborator: { [collaboratorId: string]: Split } = {};

        trackSplits.forEach((split) => {
            trackSplitsByCollaborator[split.collaborator.id] = split;
        });

        // Add splits to splitsToUpdate or splitsToDelete
        tracksWithExistingSplits.forEach((track) => {
            // For each existing split
            track.splits.forEach((split) => {
                const collaboratorId = split.collaborator.id;
                // If it has the same collaborator as a new split
                if (trackSplitsByCollaborator[collaboratorId])
                    // Update existing split with values from new split
                    splitsToUpdateWithIdentifiers.push({
                        id: split.id,
                        collaboratorId,
                        splitRate: trackSplitsByCollaborator[collaboratorId].splitRate,
                        rateType: trackSplitsByCollaborator[collaboratorId].rateType,
                        identifier: split.identifier,
                    });
                else
                    // Otherwise delete existing split
                    splitsToDelete.push({ id: split.id });
            });
        });

        // Add splits to splitsToCreate
        // For each track with same ISRC
        tracksWithSameIsrc.forEach((track) => {
            // For each new split
            trackSplits.forEach((split) => {
                const splitToCreate: CreateCollaboratorSplitInput = {
                    identifier: track.tuid,
                    collaboratorId: split.collaborator.id,
                    splitRate: split.splitRate,
                    rateType: split.rateType,
                    splitTypeId: SPLIT_TYPE_IDS.TRACK,
                    productId: track.product!.productId
                };

                // If we aren't already updating an existing split
                if (!splitsToUpdateWithIdentifiers.find(({ collaboratorId, identifier }) =>
                    collaboratorId === splitToCreate.collaboratorId
                        && identifier === splitToCreate.identifier))
                    // Create a new split
                    splitsToCreate.push(splitToCreate);
            });
        });
    }

    const splitsToUpdate = splitsToUpdateWithIdentifiers.map(split => ({ ...split, identifier: undefined }));

    return {
        create: splitsToCreate,
        update: splitsToUpdate,
        delete: splitsToDelete,
    };
};

type Props = {
    onClose(): void;
    trackSplits: Split[];
    tracksWithSameIsrc: LabelSoundRecordingTrack[];
    isrc: string;
    productId: string;
};

const BulkSplitsModal: React.FC<Props> = (
    {
        onClose,
        trackSplits,
        tracksWithSameIsrc,
        isrc,
        productId,
    }
) => {
    const tracksWithSplits = tracksWithSameIsrc.filter(track => track.splits.length);

    const renderCollaborators = (collaboratorSplits: LabelSoundRecordingSplit[]) => (
        <div className={ `${CLASS_NAME}-info` }>
            <div className={ `${CLASS_NAME}-info-header` }>
                { formatMessage(messages.collaborators) }
            </div>
            <div className={ `${CLASS_NAME}-info-glyph` }><WarningGlyph /></div>
            <div className={ `${CLASS_NAME}-info-content` }>
                { collaboratorSplits.map((split) => (
                    <React.Fragment key={ split.collaborator.id }>
                        <span>{ split.collaborator.name }</span>
                        <span className={ `${CLASS_NAME}-info-separator` }>&middot;</span>
                    </React.Fragment>
                )) }
            </div>
        </div>
    );

    const [saveCollaboratorSplitsMutation, { error, loading }] = useSaveCollaboratorSplitsMutation(productId, true);

    const handleSave = async () => {
        try {
            await saveCollaboratorSplitsMutation({ variables: getSaveCollaboratorSplitsVariables(tracksWithSameIsrc, trackSplits) });
        } catch {
            return;
        }

        onClose();
    };

    const handleCancel = () => {
        if (!loading)
            onClose();
    };

    const renderHeaderMessage = () => {
        const messageParts = formatMessage(messages.bulkSplitsModalMessage, { count: tracksWithSameIsrc.length }).split('{bold}');

        return (
            <div className={ `${CLASS_NAME}-message` }>
                { messageParts[0] }<strong>{ messageParts[1] }</strong>{ messageParts[2] }
            </div>
        );
    };

    const renderTracks = (tracks: LabelSoundRecordingTrack[]) =>
        tracks.map((track) => {
            const product = track.product!;
            const productName = product.deliveredVersion
                ? `${product.productName} ${product.deliveredVersion}`
                : product.productName;

            return (
                <div key={ product.productId!.toString() } className={ `${CLASS_NAME}-track` }>
                    <div className={ `${CLASS_NAME}-track-title` }>
                        { track.name }
                    </div>
                    { track.splits?.length > 0 && renderCollaborators(track.splits) }
                    <div className={ `${CLASS_NAME}-info` }>
                        <div className={ `${CLASS_NAME}-info-header` }>
                            { formatMessage(messages.product) }
                        </div>
                        <div className={ `${CLASS_NAME}-info-content` }>
                            { renderConfigurationIcon(product.productConfiguration) }
                            <ProductDisplayType
                                productConfiguration={ product.productConfiguration }
                                configuration={ product.configuration }
                                format={ product.format }
                                typeOfVideo={ product.typeOfVideo }
                            />
                            <span className={ `${CLASS_NAME}-info-separator` }>&middot;</span>
                            <span className={ `${CLASS_NAME}-info-product-name` }>{ productName }</span>
                            <span>{ `(UPC: ${product.displayUpc})` }</span>
                        </div>
                    </div>
                </div>
            );
        });

    return (
        <Modal
            className={ CLASS_NAME }
            onRequestClose={ handleCancel }
            headerLabel={ formatMessage(messages.applySameSplitAllTracks) }
            isOpen
            footer={ (
                <div className={ `${CLASS_NAME}-footer` }>
                    <Button
                        className={ `${CLASS_NAME}-footer-button-cancel` }
                        onClick={ handleCancel }
                        disabled={ loading }
                    >
                        { formatMessage(messages.noCancel) }
                    </Button>
                    { error && (
                        <span
                            className={ `${CLASS_NAME}-validation-error-message` }
                        >
                            { formatMessage(messages.failedToApply) }
                        </span>
                    ) }
                    <LoadingButton
                        className={ `${CLASS_NAME}-footer-button-add` }
                        variant="primary"
                        onClick={ handleSave }
                        loading={ loading }
                    >
                        { formatMessage(messages.yesApplyToAllTracksWithSameIsrc, { count: tracksWithSameIsrc.length }) }
                    </LoadingButton>
                </div>
            ) }
        >
            <div
                className={ `${CLASS_NAME}-content` }
            >
                { renderHeaderMessage() }
                <div className={ `${CLASS_NAME}-tracks-heading` }>
                    <div>{ formatMessage(messages.tracks) }</div>
                    <div>{ `${formatMessage(messages.isrc)} ${isrc}` }</div>
                </div>
                <div className={ `${CLASS_NAME}-track-list` }>
                    { renderTracks(tracksWithSameIsrc) }
                </div>
                { tracksWithSplits.length > 0 && (
                    <div
                        className={ `${CLASS_NAME}-warning-message` }
                    >
                        { formatMessage(messages.existingCollaboratorSplitsOverwritten, { count: tracksWithSplits.length }) }
                    </div>
                ) }
            </div>
        </Modal>
    );
};

export default BulkSplitsModal;
