import React from 'react';
import {
    Button,
    Card,
    Field,
    NumberInput,
    Label as LabelDisplay,
    Checkbox,
} from '@theorchard/suite-components';
import {
    BRAND_AWAL,
    formatMessage,
    useIdentity,
} from '@theorchard/suite-frontend';
import { GlyphIcon } from '@theorchard/suite-icons';
import cx from 'classnames';
import { Decimal } from 'decimal.js';
import { isEqual } from 'lodash';
import RegisterNewSongWriter from 'src/components/registerNewSongwriter';
import SongWriterSelector from 'src/components/songWriterSelector';
import { getSum, emptySongWriter } from 'src/utils/helpers';
import type { PublishingCreateSongWriterMutation } from 'src/data/mutations/createSongWriter/__generated__/createSongWriter';
import type { SongWriterState, SongWriter, Label } from 'src/types';

const CLASSNAME = 'CompositionSongWriterList';

interface Props {
    label: Label | null;
    songWriters: SongWriterState[];
    onChange: (songWriters: SongWriterState[]) => void;
    containsPublicDomain: boolean;
    containsSample: boolean;
    isSubmitted?: boolean;
}

const CompositionSongWriterList: React.FC<Props> = ({
    label,
    songWriters,
    onChange,
    containsPublicDomain,
    containsSample,
    isSubmitted,
}) => {
    const { defaultBrand } = useIdentity();
    const [isNewSongWriterModalOpen, setIsNewSongWriterModalOpen] =
        React.useState(false);

    const addEmptySongWriter = () => {
        onChange([...songWriters, emptySongWriter]);
    };

    type ContributionType = 'arranger' | 'music' | 'lyrics';

    const onChangedSongWriterContribution = (
        changedSongWriter: SongWriterState,
        contributionType: ContributionType
    ) => {
        changedSongWriter = updateContributions(
            contributionType,
            changedSongWriter
        );
        onChangedSongWriter(changedSongWriter);
    };

    const updateContributions = (
        contributionType: ContributionType,
        changedSongWriter: SongWriterState
    ) => {
        switch (contributionType) {
            case 'arranger':
                return {
                    ...changedSongWriter,
                    hasMusicContribution: false,
                    hasLyricsContribution: false,
                };
            case 'lyrics':
            case 'music':
                return { ...changedSongWriter, hasArrangerContribution: false };
        }
    };

    const onChangedSongWriter = (
        changedSongWriter: SongWriterState,
        targetId?: string,
        agreementId?: string
    ) => {
        const songWriterIdToChange =
            targetId === undefined ? changedSongWriter.id : targetId;
        const songWriterAgreementId =
            agreementId === undefined
                ? changedSongWriter.agreementId
                : agreementId;
        const newSongWriters = songWriters.map(sw =>
            sw.id === songWriterIdToChange &&
            sw.agreementId === songWriterAgreementId
                ? changedSongWriter
                : sw
        );
        onChange(newSongWriters);
    };

    const summationPercent = getSum(
        songWriters.map(sw => new Decimal(sw.split || 0))
    ).toString();

    const renderTotalRow = () => (
        <div className="NewSong-songwriters-total-ownership">
            <span
                className={cx({
                    unbound: new Decimal(summationPercent).gt(100),
                    bound: new Decimal(summationPercent).eq(100),
                })}
            >
                {summationPercent}%
            </span>
            <span> {formatMessage('generic.ownership')}</span>
        </div>
    );

    const proDisplayText = (songWriter: SongWriterState) => {
        if (songWriter.controlled && !songWriter.pro)
            return formatMessage(`${CLASSNAME}.controlledWritersApprovedNA`);
        return songWriter.pro;
    };

    const ipiDisplayText = (songWriter: SongWriterState) => {
        if (songWriter.controlled && !songWriter.ipi)
            return formatMessage(`${CLASSNAME}.controlledWritersApprovedNA`);
        return songWriter.ipi;
    };

    const hasMusicContribution = songWriters.some(i => i.hasMusicContribution);

    const publicDomainSamplingAvailable =
        containsPublicDomain || containsSample;

    const onCreated = (newSongWriter?: SongWriterState) => {
        const newSongWriters = [
            ...songWriters.filter(sw => sw.id !== 'addNewSongwriter'), // Remove "Add New" item that triggered this
            ...(newSongWriter ? [newSongWriter] : []), // Add (if) the new one
        ];

        onChange(newSongWriters);
        setIsNewSongWriterModalOpen(false);
    };

    const onNewSongWriter = (
        createSongWriterMutationResult?: PublishingCreateSongWriterMutation
    ) => {
        const swAgreement =
            createSongWriterMutationResult?.createPublishingSongWriter
                ?.agreements[0];
        const songWriter = swAgreement?.songWriter;

        if (!createSongWriterMutationResult || !swAgreement || !songWriter) {
            onCreated();
            return;
        }

        const flatSongWriterAgreement: SongWriterState = {
            id: songWriter.id,
            agreementId: swAgreement.id,
            legalName: songWriter.legalName,
            ipi: songWriter.ipi?.toString() || null,
            pro: songWriter.pro || null,
            controlled: swAgreement.controlled,
            split: '0',
            hasMusicContribution: false,
            hasArrangerContribution: false,
            hasLyricsContribution: false,
            publisherName: swAgreement.publisher?.name || '',
        };

        onCreated(flatSongWriterAgreement);
    };

    return (
        <Card suite>
            {isNewSongWriterModalOpen && (
                <RegisterNewSongWriter
                    isOpen
                    onClose={onNewSongWriter}
                    headerLabel={formatMessage(
                        'songWriterManager.registerNewSongWriter'
                    )}
                />
            )}

            <div className="NewSong-header">
                <div className="NewSong-header-title">
                    {formatMessage('generic.songWriters')}
                </div>
                <div className="NewSong-header-subtitle">
                    {formatMessage(`${CLASSNAME}.songWritersSubtitle`)}
                </div>
            </div>

            <div
                className={`NewSong-songwriters-grid ${publicDomainSamplingAvailable ? 'NewSong-songwriters-grid-pub-column' : ''}`}
            >
                <LabelDisplay
                    text={formatMessage('generic.songWriter')}
                    help={{
                        message: formatMessage(
                            `${CLASSNAME}.controlledWritersNeedRequiredProps`,
                            {
                                brand:
                                    defaultBrand === BRAND_AWAL
                                        ? 'awal'
                                        : 'theorchard',
                            }
                        ),
                        id: 'songWriterLabelHelp',
                    }}
                    hasError={!songWriters[0]?.id}
                />
                <LabelDisplay text={formatMessage('generic.pro')} />
                <LabelDisplay text={formatMessage('generic.ipi')} />
                <LabelDisplay text={formatMessage('generic.ownership')} />
                <LabelDisplay text={formatMessage('generic.contribution')} />
                {publicDomainSamplingAvailable && (
                    <div className="publicDomainSamplingHeader" />
                )}
                <div className="closeHeader" />

                {songWriters.map(songWriter => (
                    <React.Fragment
                        key={songWriter.id + songWriter.agreementId}
                    >
                        <div className="NewSong-songwriters-name">
                            <SongWriterSelector
                                withAddNew
                                isClearable={false}
                                label={label || null}
                                defaultValue={
                                    songWriter.agreementId ? [songWriter] : null
                                }
                                excludeFilter={{
                                    agreementIds: songWriters.map(
                                        sw => sw.agreementId
                                    ),
                                }}
                                onChange={(swOptions: SongWriter[] | null) => {
                                    if (!swOptions) return;

                                    // This is not a multiple selector, so it returns only an item
                                    const swOption =
                                        swOptions[0] as unknown as SongWriterState;

                                    // Avoid having same songwriter twice
                                    if (
                                        songWriters.find(
                                            sw =>
                                                sw.id === swOption.id &&
                                                sw.agreementId ===
                                                    swOption.agreementId
                                        )
                                    )
                                        return;

                                    if (swOption.id === 'addNewSongwriter') {
                                        // Opens the CreateSongWriterModal to replace or delete current item
                                        onChangedSongWriter(
                                            {
                                                ...emptySongWriter,
                                                id: 'addNewSongwriter',
                                            },
                                            songWriter.id
                                        );
                                        setIsNewSongWriterModalOpen(true);
                                    } else {
                                        const songWriterWithState = {
                                            ...swOption,
                                            split: '0',
                                            hasMusicContribution: false,
                                            hasLyricsContribution: false,
                                            hasArrangerContribution: false,
                                            containsPublicDomain: false,
                                            containsSample: false,
                                            label: { uuid: label?.uuid },
                                        } as unknown as SongWriterState;

                                        onChangedSongWriter(
                                            songWriterWithState,
                                            songWriter.id,
                                            songWriter.agreementId
                                        );
                                    }
                                }}
                            />
                        </div>

                        <div className="NewSong-songwriters-pro">
                            {proDisplayText(songWriter)}
                        </div>

                        <div className="NewSong-songwriters-ipi">
                            {ipiDisplayText(songWriter)}
                        </div>

                        <div className="NewSong-songwriters-ownership">
                            <Field
                                controlId="ownership"
                                labelText=""
                                errorMessage={
                                    isSubmitted && summationPercent !== '100'
                                        ? formatMessage(
                                              'errors.ownershipNot100'
                                          )
                                        : undefined
                                }
                            >
                                <NumberInput
                                    disabled={!songWriter.id}
                                    value={songWriter.split || ''}
                                    onChange={splitNumValue => {
                                        onChangedSongWriter({
                                            ...songWriter,
                                            split: splitNumValue,
                                        });
                                    }}
                                    decimalPrecision={2}
                                />
                            </Field>
                        </div>

                        <div className="NewSong-songwriters-contribution">
                            <Field
                                controlId="contribution"
                                labelText=""
                                errorMessage={
                                    isSubmitted && !hasMusicContribution
                                        ? formatMessage(
                                              'errors.noMusicContribution'
                                          )
                                        : undefined
                                }
                            >
                                <Checkbox
                                    id={`contribution_music_${songWriter.id}_${songWriter.agreementId}`}
                                    disabled={!songWriter.id}
                                    label={formatMessage('generic.music')}
                                    checked={songWriter.hasMusicContribution}
                                    onChange={evt => {
                                        onChangedSongWriterContribution(
                                            {
                                                ...songWriter,
                                                hasMusicContribution:
                                                    evt.target.checked,
                                            },
                                            'music'
                                        );
                                    }}
                                />
                                <Checkbox
                                    id={`contribution_lyric_${songWriter.id}_${songWriter.agreementId}`}
                                    disabled={!songWriter.id}
                                    label={formatMessage('generic.lyrics')}
                                    checked={songWriter.hasLyricsContribution}
                                    onChange={evt => {
                                        onChangedSongWriterContribution(
                                            {
                                                ...songWriter,
                                                hasLyricsContribution:
                                                    evt.target.checked,
                                            },
                                            'lyrics'
                                        );
                                    }}
                                />
                                <Checkbox
                                    id={`contribution_arranger_${songWriter.id}_${songWriter.agreementId}`}
                                    disabled={!songWriter.id}
                                    label={formatMessage('generic.arranger')}
                                    checked={songWriter.hasArrangerContribution}
                                    onChange={evt => {
                                        onChangedSongWriterContribution(
                                            {
                                                ...songWriter,
                                                hasArrangerContribution:
                                                    evt.target.checked,
                                            },
                                            'arranger'
                                        );
                                    }}
                                />
                            </Field>
                        </div>

                        {publicDomainSamplingAvailable && (
                            <div className="NewSong-songwriters-publicDomainSampling">
                                {containsPublicDomain && (
                                    <Checkbox
                                        id={`pub_domain_${songWriter.id}`}
                                        className="NewSong-songwriters-publicDomain"
                                        disabled={!songWriter.id}
                                        label={formatMessage(
                                            'generic.publicDomain'
                                        )}
                                        checked={
                                            songWriter?.containsPublicDomain ??
                                            false
                                        }
                                        onChange={({ target }) =>
                                            onChangedSongWriter({
                                                ...songWriter,
                                                containsPublicDomain:
                                                    target.checked,
                                            })
                                        }
                                    />
                                )}
                                {containsSample && (
                                    <Checkbox
                                        id={`sampling_${songWriter.id}`}
                                        className="NewSong-songwriters-sampling"
                                        disabled={!songWriter.id}
                                        label={formatMessage(
                                            'generic.sampling'
                                        )}
                                        checked={
                                            songWriter?.containsSample ?? false
                                        }
                                        onChange={({ target }) =>
                                            onChangedSongWriter({
                                                ...songWriter,
                                                containsSample: target.checked,
                                            })
                                        }
                                    />
                                )}
                            </div>
                        )}
                        <div
                            className="NewSong-alternate-field-x"
                            onClick={() =>
                                onChange(
                                    songWriters.filter(
                                        sw => !isEqual(sw, songWriter)
                                    )
                                )
                            }
                        >
                            <GlyphIcon name="close" size={16} />
                        </div>
                    </React.Fragment>
                ))}
            </div>

            <Button
                variant="link"
                // We need to prevent adding more than one "empty" rows as we use the empty identifier rather than indexes
                disabled={songWriters.some(sw => !sw.id)}
                className="icon-left"
                onClick={addEmptySongWriter}
            >
                <GlyphIcon name="plus" size={12} />
                {formatMessage('newSong.addCoWriter')}
            </Button>

            <div className="NewSong-divider" />

            {renderTotalRow()}
        </Card>
    );
};

export default CompositionSongWriterList;
