﻿import type { FC } from 'react';
import React, { useEffect, useState, useMemo } from 'react';
import {
    Alert,
    Form,
    Modal,
    Sidecar,
    Select,
} from '@theorchard/suite-components';
import { GlyphIcon } from '@theorchard/suite-icons';
import _ from 'lodash';
import { APPROVAL, BLOCKLIST_CATEGORY_ID } from 'src/constants';
import { useApproveProductMutation } from 'src/data/mutations/approve';
import { useUpsertTracksAudioAttributesMutation } from 'src/data/mutations/upsertTracksAudioAttributes';
import { useUpsertTracksAudioAttributesEditsMutation } from 'src/data/mutations/upsertTracksAudioAttributesEdits';
import { useUpsertTracksRightsAttributesMutation } from 'src/data/mutations/upsertTracksRightsAttributes';
import { useUpsertTracksRightsAttributesEditsMutation } from 'src/data/mutations/upsertTracksRightsAttributesEdits';
import {
    useCannedResponseNoteQuery,
    useCannedResponsesQuery,
} from 'src/data/queries';
import {
    clearTrackAudioAttributesEdits,
    clearTrackRightsAttributesEdits,
    getAudioAttributesInput,
    getRightsAttributesInput,
    isMissingTrackAttributes,
    replicateTrackAudioAttributesFromEdits,
    replicateTrackRightsAttributesFromEdits,
} from 'src/utils/attributes';
import { useDisplayAudioAttributeModalFF } from 'src/utils/features';
import { isPotentialAudioInfringementVal } from 'src/utils/product';
import type { Product } from 'src/data/queries/product/types';
import type { MergedProduct } from 'src/product/product';
import type { CannedResponseNote } from 'src/types';

export const CLASS_NAME = 'ProductModalApprovalSidecar';
const INTL_PREFIX = 'contentReview.productModalApprovalSidecar';
const MIXED = 'Mixed';

const APPROVAL_REASON_DEFINITIONS_LINK =
    'https://docs.google.com/spreadsheets/d/1PTCjyMuj0MI5Pad8DTjmXHIzpIm1-CBTkgxBYqsDZyk/edit?pli=1&gid=1820067481#gid=1820067481';

export interface Props {
    product: Product;
    mergedProduct: MergedProduct;
    isApprovalNoteRequired: boolean;
    isOpen: boolean;
    closeModal: () => void;
    additionalNotes: string;
    onReviewCompleted: (status: string, eventType?: string) => void;
    onAdditionalNotesChange: (val: string) => void;
    productReviewQueueId: number;
    approvalNote: string;
    handleSetApprovalNote: (note: string) => void;
    approvalReason: string;
    handleSetApprovalReasons: (reason: string) => void;
    trackApprovalReasons: Record<string, string>;
    handleSetTrackApprovalReasons: (reasons: Record<string, string>) => void;
    handleTrackApprovalChange: (tuid: string, cannedResponseId: string) => void;
}

const ProductModalApprovalSidecar: FC<Props> = ({
    product,
    mergedProduct,
    isApprovalNoteRequired,
    isOpen,
    closeModal,
    additionalNotes,
    onAdditionalNotesChange,
    onReviewCompleted,
    productReviewQueueId,
    approvalNote,
    handleSetApprovalNote,
    approvalReason,
    handleSetApprovalReasons,
    trackApprovalReasons,
    handleSetTrackApprovalReasons,
    handleTrackApprovalChange,
}) => {
    const { data } = useCannedResponsesQuery({
        reviewContext: APPROVAL,
    });

    const [isConfirmDisabled, setIsConfirmDisabled] = useState<boolean>(false);
    const [showAudioRightsAttributeModal, setShowAudioRightsAttributeModal] =
        useState<boolean>(false);
    const [showTracks, setShowTracks] = useState(false);
    const isDisplayAudioAttributeModalFFEnabled =
        useDisplayAudioAttributeModalFF();
    const tracks = Object.entries(trackApprovalReasons).map(
        ([trackId, cannedResponseId]) => ({
            trackId: parseInt(trackId, 10),
            cannedResponseId: parseInt(cannedResponseId, 10),
        })
    );
    const triggerApproveProductMutation = useApproveProductMutation(
        productReviewQueueId,
        approvalNote,
        approvalReason,
        undefined, // TODO: Will be replaced by a new variable once dynamic reasons are introduced in a separate ticket
        tracks,
        onReviewCompleted
    );

    const [updateTracksAudioAttributesEdits] =
        useUpsertTracksAudioAttributesEditsMutation();
    const [updateTracksRightsAttributesEdits] =
        useUpsertTracksRightsAttributesEditsMutation();
    const [updateTracksAudioAttributeCallback] =
        useUpsertTracksAudioAttributesMutation();
    const [updateTracksRightsAttributeCallback] =
        useUpsertTracksRightsAttributesMutation();

    useEffect(() => {
        const shouldConfirmBeDisabled = Boolean(
            isApprovalNoteRequired &&
                (!approvalReason ||
                    (approvalReason === '69' && !additionalNotes.trim()) ||
                    Object.values(trackApprovalReasons).some(
                        (reason: string): boolean =>
                            !reason ||
                            (reason === '69' && !additionalNotes.trim())
                    ))
        );
        setIsConfirmDisabled(shouldConfirmBeDisabled);
    }, [
        approvalReason,
        isApprovalNoteRequired,
        additionalNotes,
        trackApprovalReasons,
    ]);

    const handleApprovalNoteChange = (data: CannedResponseNote) => {
        handleSetApprovalNote(data.noteKeyword);
    };

    const [getApprovalNote] = useCannedResponseNoteQuery(
        { cannedResponseId: '', languageCode: '' },
        handleApprovalNoteChange
    );

    const handleApprovalReasonChange = (cannedResponseId: string) => {
        handleSetApprovalReasons(cannedResponseId);
        getApprovalNote({
            variables: {
                cannedResponseId,
                languageCode: 'en',
            },
        });

        // Set all tracks to this approval reason
        const updatedTrackReasons: Record<string, string> = {};
        infringedTracks.forEach(track => {
            updatedTrackReasons[track.tuid.toString()] = cannedResponseId;
        });
        handleSetTrackApprovalReasons(updatedTrackReasons);
    };

    const updateFinalApprovalNote = async () => {
        const noteToAdd = additionalNotes?.trim();
        if (!noteToAdd) return;
        handleSetApprovalNote(
            approvalNote ? `${approvalNote.trim()}\n${noteToAdd}` : noteToAdd
        );
    };

    const resetAudioAttributesEdits = async () => {
        await updateTracksAudioAttributesEdits({
            variables: {
                input: product.tracks.map(({ tuid }) => ({
                    tuid,
                    audioAttributeIds: [],
                })),
            },
        });
    };

    const resetRightsAttributesEdits = async () => {
        await updateTracksRightsAttributesEdits({
            variables: {
                input: product.tracks.map(({ tuid }) => ({
                    tuid,
                    rightsAttributeIds: [],
                })),
            },
        });
    };

    const replicateAndResetAudioAttributesEdits = async () => {
        replicateTrackAudioAttributesFromEdits(mergedProduct?.getTrackList());
        clearTrackAudioAttributesEdits(mergedProduct?.getTrackList());
        await resetAudioAttributesEdits();
    };

    const replicateAndResetRightsAttributesEdits = async () => {
        replicateTrackRightsAttributesFromEdits(mergedProduct?.getTrackList());
        clearTrackRightsAttributesEdits(mergedProduct?.getTrackList());
        await resetRightsAttributesEdits();
    };

    const handleFormSubmission = async () => {
        if (isDisplayAudioAttributeModalFFEnabled) {
            const {
                foundMissingAudioAttributes,
                foundMissingRightsAttributes,
            } = isMissingTrackAttributes(
                mergedProduct?.getTrackList(),
                product.tracks
            );

            if (foundMissingAudioAttributes || foundMissingRightsAttributes) {
                setShowAudioRightsAttributeModal(true);
                return;
            }
        }

        setIsConfirmDisabled(true);
        await updateFinalApprovalNote();
        await triggerApproveProductMutation();
        await replicateAndResetAudioAttributesEdits();
        await replicateAndResetRightsAttributesEdits();
        await updateTracksAudioAttributeCallback({
            variables: {
                input: getAudioAttributesInput(
                    mergedProduct?.getTrackList(),
                    product.tracks
                ),
            },
        });
        await updateTracksRightsAttributeCallback({
            variables: {
                input: getRightsAttributesInput(
                    mergedProduct?.getTrackList(),
                    product.tracks
                ),
            },
        });
        closeModal();
    };

    const handleApproveMissingAudioAttribute = async () => {
        setIsConfirmDisabled(true);
        await updateFinalApprovalNote();
        await triggerApproveProductMutation();
        await replicateAndResetAudioAttributesEdits();
        await replicateAndResetRightsAttributesEdits();
        await updateTracksAudioAttributeCallback({
            variables: {
                input: getAudioAttributesInput(
                    mergedProduct?.getTrackList(),
                    product.tracks
                ),
            },
        });
        await updateTracksRightsAttributeCallback({
            variables: {
                input: getRightsAttributesInput(
                    mergedProduct?.getTrackList(),
                    product.tracks
                ),
            },
        });
        closeModal();
    };
    const infringedTracks = mergedProduct?.tracks
        ? _(mergedProduct.tracks)
              .values()
              .filter(track =>
                  track.validations?.some(v =>
                      isPotentialAudioInfringementVal(v.code)
                  )
              )
              .sortBy(track => track.trackNumber?.currentValue ?? 0)
              .value()
        : [];
    const showMixedApprovalReason = useMemo(() => {
        return (
            Object.keys(trackApprovalReasons).length > 0 &&
            Object.values(trackApprovalReasons).some(
                reason => reason !== String(approvalReason)
            )
        );
    }, [trackApprovalReasons, approvalReason]);

    const approvalReasonOptions = (data ?? [])
        .filter(
            item => item.cannedResponseCategory.id !== BLOCKLIST_CATEGORY_ID
        )
        .map(item => ({
            label: item.keyword,
            value: item.cannedResponseId,
        }));

    return (
        <div>
            <Sidecar
                className={CLASS_NAME}
                isOpen={isOpen}
                onRequestClose={closeModal}
                title={$t(`${INTL_PREFIX}.title`)}
                confirmTitle={$t(`${INTL_PREFIX}.confirm`)}
                onConfirm={handleFormSubmission}
                testId={CLASS_NAME}
                confirmDisabled={isConfirmDisabled}
            >
                <Form
                    className={`${CLASS_NAME}-Form`}
                    data-testid={`${CLASS_NAME}-Form`}
                    style={{ width: '95%' }}
                >
                    {isApprovalNoteRequired && (
                        <Alert
                            className={`${CLASS_NAME}-Form-Notice`}
                            variant="warn"
                            testId="form-notice"
                            text={
                                <span>
                                    <div
                                        className={`${CLASS_NAME}-notice-infringement`}
                                    >
                                        {$t(
                                            `${INTL_PREFIX}.audioInfringementNotice`
                                        )}
                                    </div>
                                    <div
                                        className={`${CLASS_NAME}-approval-instruction`}
                                    >
                                        {$t(
                                            `${INTL_PREFIX}.approvalInstruction`
                                        )}
                                    </div>
                                    <div
                                        className={`${CLASS_NAME}-approval-definitions`}
                                    >
                                        {$tx(
                                            `${INTL_PREFIX}.approvalReasonDefinition`,
                                            {
                                                link: ({ children }) => (
                                                    <a
                                                        className={`${CLASS_NAME}-approval-definitions-link`}
                                                        href={
                                                            APPROVAL_REASON_DEFINITIONS_LINK
                                                        }
                                                        target="_blank"
                                                        rel="noreferrer"
                                                    >
                                                        {children}
                                                    </a>
                                                ),
                                            }
                                        )}
                                    </div>
                                </span>
                            }
                        />
                    )}
                    {isApprovalNoteRequired && (
                        <Form.Group
                            controlId="approval-reason"
                            data-testid="form-group-approval-reason"
                        >
                            <Form.Label>
                                {$t(`${INTL_PREFIX}.approvalReason`)}
                            </Form.Label>
                            <Select
                                testId="approval-reason-select"
                                options={approvalReasonOptions}
                                placeholder={$t(
                                    `${INTL_PREFIX}.selectApprovalReason`
                                )}
                                selectedValue={
                                    showMixedApprovalReason
                                        ? MIXED
                                        : approvalReason
                                }
                                onChange={option => {
                                    const cannedResponseId =
                                        option?.value ?? '';
                                    handleApprovalReasonChange(
                                        cannedResponseId
                                    );
                                }}
                            />
                            {!showMixedApprovalReason && approvalReason && (
                                <div
                                    className={`${CLASS_NAME}-select-approval-reason-notice`}
                                >
                                    {$t(
                                        `${INTL_PREFIX}.selectApprovalReasonNotice`
                                    )}
                                </div>
                            )}
                        </Form.Group>
                    )}
                    {infringedTracks.length > 0 && (
                        <div className={`${CLASS_NAME}-tracks`}>
                            <div
                                className={`${CLASS_NAME}-tracks-header`}
                                onClick={() => setShowTracks(prev => !prev)}
                            >
                                <Form.Label>
                                    {$t(`${INTL_PREFIX}.seeTracksIndividually`)}
                                </Form.Label>

                                <GlyphIcon
                                    name={
                                        showTracks
                                            ? 'doubleChevronUp'
                                            : 'doubleChevronDown'
                                    }
                                    size={12}
                                />
                            </div>

                            {showTracks && (
                                <>
                                    {infringedTracks.map(track => (
                                        <Form.Group
                                            key={track.tuid}
                                            controlId={`approval-reason-${track.tuid}`}
                                            data-testid={`form-group-approval-reason-${track.tuid}`}
                                            className={`${CLASS_NAME}-tracks-form-group`}
                                        >
                                            <Form.Label
                                                className={`${CLASS_NAME}-tracks-name`}
                                            >
                                                {$t(`${INTL_PREFIX}.track`)}{' '}
                                                {track.trackNumber.currentValue}
                                                : {track.trackName.currentValue}
                                            </Form.Label>
                                            <Form.Label
                                                className={`${CLASS_NAME}-tracks-approval-reason`}
                                            >
                                                {$t(
                                                    `${INTL_PREFIX}.approvalReason`
                                                )}
                                            </Form.Label>
                                            <Select
                                                testId={`approval-reason-select-${track.tuid}`}
                                                options={approvalReasonOptions}
                                                placeholder={$t(
                                                    `${INTL_PREFIX}.selectApprovalReason`
                                                )}
                                                selectedValue={
                                                    trackApprovalReasons[
                                                        track.tuid
                                                    ] ?? ''
                                                }
                                                onChange={option => {
                                                    const cannedResponseId =
                                                        option?.value ?? '';
                                                    handleTrackApprovalChange(
                                                        track.tuid.toString(),
                                                        cannedResponseId
                                                    );
                                                }}
                                            />
                                        </Form.Group>
                                    ))}
                                </>
                            )}
                        </div>
                    )}
                    <Form.Group
                        controlId="additional-notes-approve"
                        data-testid="form-group-additional-notes-approval"
                    >
                        <Form.Label>{$t('common.additionalNotes')}</Form.Label>
                        <Form.Control
                            as="textarea"
                            data-testid="form-control-additional-notes-approval"
                            rows={24}
                            value={additionalNotes}
                            placeholder={$t(
                                `${INTL_PREFIX}.additionalNotesPlaceholder.approval`
                            )}
                            onChange={e =>
                                onAdditionalNotesChange(e.currentTarget.value)
                            }
                        />
                    </Form.Group>
                </Form>
            </Sidecar>
            {showAudioRightsAttributeModal && (
                <Modal
                    testId="missing-audio-attributes-modal"
                    className={`${CLASS_NAME}-audio-attribute-modal`}
                    title={$t(`${INTL_PREFIX}.audioAttributeModalTitle`)}
                    isOpen={showAudioRightsAttributeModal}
                    confirmTitle={$t(
                        `${INTL_PREFIX}.audioAttributeModalApproveButton`
                    )}
                    onRequestClose={() =>
                        setShowAudioRightsAttributeModal(false)
                    }
                    onConfirm={handleApproveMissingAudioAttribute}
                >
                    <div className={`${CLASS_NAME}-audio-attribute-modal-body`}>
                        <p>
                            {$tx(`${INTL_PREFIX}.audioAttributeModalBody`, {
                                bold: ({ children }) => <b>{children}</b>,
                            })}
                        </p>
                    </div>
                </Modal>
            )}
        </div>
    );
};

export default ProductModalApprovalSidecar;
