import React, { useEffect, useReducer, useState } from 'react';
import {
    LoadingIndicator,
    InfoMessage,
    ErrorMessage,
} from '@theorchard/suite-components';
import { Page, filterData, useToast } from '@theorchard/suite-frontend';
import { ROUTE_SONG } from 'src/constants';
import { FeaturedInput, Priority } from 'src/data/globalTypes';
import { useUpdateContributionMutation } from 'src/data/mutations/updateNrContribution/updateNrContribution';
import { useUpdateSoundRecordingMutation } from 'src/data/mutations/updateNrSoundRecording/updateNrSoundRecording';
import { useNrSoundRecordingByIdQuery } from 'src/data/queries';
import { ensurePriorityType } from 'src/utils/formatter';
import { useRouteParams } from 'src/utils/route';
import {
    recordCancelUpdateClick,
    recordUpdateClick,
} from 'src/utils/segment/clickEvents';
import { recordMetadataEdits } from 'src/utils/segment/editEvents';
import PageHeader from './components/songPageHeader';
import { SET_INITIAL_SONG, SET_INITIAL_CONTRIB } from './constants';
import ContributorsPage from './pages/contributors';
import DeliveryPage from './pages/delivery';
import MetadataPage from './pages/metadata';
import { metadataInitialState, metadataReducer } from './reducer';
import { MutationErrors, ValidationErrors } from './songPageAlerts';
import { formatDuration } from './utils';
import type { SongRouteParams } from './types';

export const CLASSNAME = 'SongPage';
const METADATA_TAB = 'metadata';
const CONTRIBUTORS_TAB = 'contributors';
const DELIVERY_TAB = 'delivery';

const SongPage = () => {
    const [metadataState, dispatchMetadata] = useReducer(
        metadataReducer,
        metadataInitialState
    );
    const [params] = useRouteParams<SongRouteParams>(ROUTE_SONG);
    const [resetForm, setResetForm] = useState(false);
    const [editing, setEditing] = useState(false);
    const tabs = {
        [METADATA_TAB]: MetadataPage,
        [CONTRIBUTORS_TAB]: ContributorsPage,
        [DELIVERY_TAB]: DeliveryPage,
    };

    // Query to fetch NrSoundRecording data
    const {
        data: song,
        contributions,
        loading,
        error,
    } = useNrSoundRecordingByIdQuery({ id: params.nrSrId });
    useEffect(() => {
        dispatchMetadata({ type: SET_INITIAL_SONG, song, value: '', name: '' });
    }, [song]);

    useEffect(() => {
        dispatchMetadata({
            type: SET_INITIAL_CONTRIB,
            contributions: contributions ?? [],
            value: '',
            name: '',
        });
    }, [contributions]);

    // Mutations to update data on tabs
    const { updateSoundRecording, error: srMutationError } =
        useUpdateSoundRecordingMutation({
            id: params.nrSrId,
            featuredArtistIds: [],
            mainArtist: '',
            primaryArtistIds: [],
            priority: Priority.LOW,
            recordingTitle: '',
            recordingType: 'AUDIO',
        });
    const { updateContribution, error: contribMutationError } =
        useUpdateContributionMutation(
            { id: '', featured: FeaturedInput.FEATURED },
            params.nrSrId
        );

    const addToast = useToast();
    const handleUpdateClicked = () => {
        setEditing(false);
        const srMutation = updateSoundRecording({
            variables: {
                // mandatory fields in mutation.
                id: params.nrSrId,
                featuredArtistIds:
                    metadataState.metadata.fields.featuredArtists.map(
                        a => a.id
                    ),
                mainArtist: metadataState.metadata.fields.mainArtist,
                primaryArtistIds:
                    metadataState.metadata.fields.primaryArtists.map(a => a.id),
                // editable fields only
                priority: ensurePriorityType(
                    metadataState.metadata.fields.priority
                ),
                version: metadataState.metadata.fields.version,
                albumName: metadataState.metadata.fields.albumName,
                catalogNumber: metadataState.metadata.fields.catalogNumber,
                recordingType: metadataState.metadata.fields.recordingType,
                recordingTitle: metadataState.metadata.fields.recordingTitle,
                countryOfLabel: metadataState.metadata.fields.countryOfLabel,
                countryOfMaster: metadataState.metadata.fields.countryOfMaster,
                recordingYear: metadataState.metadata.fields.recordingYear
                    ? parseInt(metadataState.metadata.fields.recordingYear, 10)
                    : null,
                firstReleaseYear: metadataState.metadata.fields.firstReleaseYear
                    ? parseInt(
                          metadataState.metadata.fields.firstReleaseYear,
                          10
                      )
                    : null,
                originalLabel: metadataState.metadata.fields.originalLabel,
                countriesOfRecording:
                    metadataState.metadata.fields.countriesOfRecording?.map(
                        c => c.territoryCodeA2
                    ),
                duration:
                    metadataState.metadata.fields.formattedDuration !== '-'
                        ? formatDuration(
                              metadataState.metadata.fields.formattedDuration
                          )
                        : null,
                totalFeaturedPerformers: metadataState.metadata.fields
                    .totalFeaturedPerformers
                    ? parseInt(
                          metadataState.metadata.fields.totalFeaturedPerformers,
                          10
                      )
                    : null,
            },
        });
        const contribMutation = metadataState.contributors.fields.map(
            async c => {
                const filteredInstruments = filterData(c.instruments).map(i =>
                    i.trim()
                );
                await updateContribution({
                    variables: {
                        id: c.id,
                        featured: FeaturedInput[c.contributorRelationship],
                        instruments:
                            filteredInstruments.length > 0
                                ? filteredInstruments
                                : null,
                        performanceName: c.performanceName,
                        countryOfPerformance: c.countryOfContributionCode,
                        evidence: c.evidence,
                    },
                });
            }
        );
        void Promise.all([srMutation, contribMutation]).then(() =>
            addToast($t(`neighbouringRights.songPage.generated`), {
                variant: 'success',
            })
        );
        recordUpdateClick();
        if (song && contributions)
            recordMetadataEdits(song, contributions, metadataState);
    };

    useEffect(() => {
        if (resetForm) {
            setEditing(false);
            dispatchMetadata({
                type: SET_INITIAL_SONG,
                song,
                value: '',
                name: '',
            });
            dispatchMetadata({
                type: SET_INITIAL_CONTRIB,
                contributions: contributions ?? [],
                value: '',
                name: '',
            });
            setResetForm(false);
        }
    }, [resetForm, setResetForm, contributions, song]);

    const handleCancelClicked = () => {
        setResetForm(true);
        setEditing(false);
        recordCancelUpdateClick();
    };

    if (error) return <ErrorMessage error={error} />;

    if (loading && !song) return <LoadingIndicator />;

    if (!song)
        return (
            <InfoMessage
                message={$t('neighbouringRights.songPage.songUnknown')}
            />
        );

    const mutationErrors = srMutationError || contribMutationError;
    const validationErrors = metadataState.metadata.errors.length > 0; // no validation on contributorsForm currently;

    return (
        <Page className={CLASSNAME}>
            <PageHeader
                song={song}
                handleUpdateClicked={handleUpdateClicked}
                handleCancelClicked={handleCancelClicked}
                disableButtons={!editing}
                errors={validationErrors}
            />
            {mutationErrors && !validationErrors && (
                <MutationErrors
                    srMutationError={srMutationError}
                    contribMutationError={contribMutationError}
                />
            )}
            {validationErrors && (
                <ValidationErrors errors={metadataState.metadata.errors} />
            )}
            <Page.Body
                currentView={params.tab}
                defaultView={METADATA_TAB}
                props={{
                    setEditing,
                    song,
                    updatingSong: editing,
                    resetForm,
                    metadataState,
                    dispatchMetadata,
                    contributions: {
                        data: contributions ?? [],
                        loading,
                    },
                }}
                views={tabs}
            />
        </Page>
    );
};

export default SongPage;
