// 'use no memo' — opt out of React Compiler memoization. `schedule` state is
// initialized undefined and populated asynchronously from an Apollo query;
// the render-path access `schedulesList.find(schedule => schedule.isAutoAdd)`
// and `schedule.isAutoAdd` crash under the compiler's memoization on the
// detail route ("Cannot read properties of undefined (reading 'isAutoAdd')").
// Mirrors the opt-outs added for the other tab/detail routes in ACC-10480.
'use no memo';

import React, { useEffect, useState } from 'react';
import {
    Alert,
    Button,
    Checkbox,
    Form,
    SkeletonLoader,
    useToast,
} from '@theorchard/suite-components';
import cx from 'classnames';
import { ErrorMessage } from '@theorchard/suite-components';
import { isEmpty, trim } from 'lodash-es';
import { useParams } from 'react-router-dom';
import { useHistory } from 'react-router-dom';
import {
    useBulkCreateUpdateScheduleAttachments,
    useBulkUpdateNrContributionsSchedule,
    useUpdateSchedule,
} from 'src/apollo/mutations/schedule';
import { PageHeader } from '../shared/pageHeader';
import { useContributorBreadcrumbs } from 'src/hooks/breadcrumbs/contributor';
import { useNRContributor } from 'src/apollo/queries/nr-contributors';
import { useScheduleById } from 'src/apollo/queries/schedule';
import { Contributions } from 'src/components/schedule-form/contributions';
import { LinkButton } from 'src/components/shared/link-button';
import { ProgressModal } from 'src/components/shared/progress-modal';
import { AUTO_ADD_TEXT } from 'src/constants';
import { getContributorScheduleDetail } from 'src/urls/frontend-royalties';
import { requiredMessage } from 'src/utils/form-validations';
import { formatSchedulesList, reorderSchedulesList } from 'src/utils/schedules';
import type { FormattedSchedule } from 'src/types/schedule';
import './styles.scss';

const EditScheduleForm = () => {
    const { contributorId, scheduleId } = useParams<{
        contributorId: string;
        scheduleId: string;
    }>();
    const history = useHistory();
    const breadcrumbs = useContributorBreadcrumbs();

    const [schedule, setSchedule] = useState<any>();
    const [isChecked, setIsChecked] = useState<boolean>(false);
    const [isSaving, setIsSaving] = useState<boolean>(false);
    const [contributions, setContributions] = useState<any>({
        assignedContributions: [],
        unassignedContributions: [],
    });
    const [schedulesList, setSchedulesList] = useState<FormattedSchedule[]>([]);
    const [errors, setErrors] = useState<any>({});

    const { data, loading } = useScheduleById(scheduleId);
    const { data: schedules } = useNRContributor(contributorId);

    const addUpdateScheduleAttachments =
        useBulkCreateUpdateScheduleAttachments();
    const updateNrContributionsSchedule =
        useBulkUpdateNrContributionsSchedule(contributorId);
    const updateSchedule = useUpdateSchedule();
    const toast = useToast();

    const existingAutoAddSchedule = schedulesList.find(
        schedule => schedule.isAutoAdd
    );

    useEffect(() => {
        if (schedules?.nrContributorById?.abacusSchedules) {
            const reorderedSchedules = reorderSchedulesList(
                schedules.nrContributorById.abacusSchedules
            );
            const formattedSchedules = formatSchedulesList(reorderedSchedules);
            setSchedulesList(formattedSchedules);
        }
    }, [schedules]);

    useEffect(() => {
        if (data?.abacusSchedule) {
            const { abacusSchedule } = data;
            if (
                !isEmpty(abacusSchedule) &&
                abacusSchedule?.targetId === contributorId
            ) {
                setSchedule({
                    attachmentCount:
                        abacusSchedule?.scheduleAttachments?.totalCount,
                    isAutoAdd: abacusSchedule?.conditions?.autoAdd,
                    scheduleId: abacusSchedule?.scheduleId,
                    scheduleName: abacusSchedule?.scheduleName,
                });
                setIsChecked(Boolean(abacusSchedule?.conditions?.autoAdd));
            }
        }
    }, [data]);

    const changeHandler = (e: any) => {
        const {
            target: { name, value },
        } = e;
        setSchedule({ ...schedule, [name]: value });
        setErrors({});
    };

    const updateAbacusSchedule = async () => {
        let input: any = { scheduleName: trim(schedule.scheduleName) };

        if (schedule.isAutoAdd !== null) {
            input = { ...input, conditions: { autoAdd: schedule.isAutoAdd } };
        }
        const variables = {
            scheduleId: schedule.scheduleId,
            input,
        };
        return await updateSchedule({ variables });
    };

    const updateScheduleAttachments = async () => {
        if (
            isEmpty(contributions.assignedContributions) &&
            isEmpty(contributions.unassignedContributions)
        )
            return await Promise.resolve();

        return await addUpdateScheduleAttachments({
            variables: {
                assignedTargetIds: contributions.assignedContributions,
                scheduleId: parseInt(scheduleId, 10),
                targetType: 'contribution',
                unassignedTargetIds: contributions.unassignedContributions,
            },
        });
    };

    const updateContributions = async () => {
        const updatedAssignedContributions =
            contributions.assignedContributions.map(
                (contributionId: string) => ({
                    contributionId,
                    abacusScheduleId: parseInt(scheduleId, 10),
                })
            );
        const updatedUnassignedContributions =
            contributions.unassignedContributions.map(
                (contributionId: string) => ({
                    contributionId,
                    abacusScheduleId: null,
                })
            );
        return await updateScheduleAttachments().then(
            async () =>
                await updateNrContributionsSchedule({
                    variables: {
                        input: [
                            ...updatedAssignedContributions,
                            ...updatedUnassignedContributions,
                        ],
                    },
                })
        );
    };

    const saveHandler = () => {
        if (!trim(schedule.scheduleName))
            return setErrors({ scheduleName: requiredMessage('Name') });

        setIsSaving(true);
        Promise.all([updateAbacusSchedule(), updateContributions()])
            .then(() => {
                toast(
                    `Changes have been successfully saved for ${schedule.scheduleName}`
                );
                history.push(
                    getContributorScheduleDetail(contributorId, scheduleId)
                );
            })
            .catch(() => {
                setErrors({ serverError: 'Something went wrong.' });
                setIsSaving(false);
            });
    };

    if (loading) return <SkeletonLoader />;

    if (isEmpty(schedule) && !loading) {
        return <ErrorMessage message="There is no data available" />;
    }

    return (
        <div className="EditScheduleForm">
            <PageHeader title="Edit Schedule" breadcrumbs={breadcrumbs} />
            <div className="EditScheduleForm-top-nav">
                {errors.serverError && (
                    <Alert variant="error" text={errors.serverError} />
                )}
                <div className="EditScheduleForm-ScheduleName">
                    <Form.Control
                        className={cx({
                            scheduleName: true,
                            error: !isEmpty(errors) && errors.scheduleName,
                        })}
                        data-testid="scheduleName"
                        name="scheduleName"
                        placeholder="Please Enter Schedule Name"
                        onChange={(e: any) => changeHandler(e)}
                        type="text"
                        value={schedule?.scheduleName}
                    />
                    {errors?.scheduleName ? (
                        <span className="error-msg">{errors.scheduleName}</span>
                    ) : null}
                </div>
                <div className="EditScheduleForm-Checkbox">
                    <Checkbox
                        checked={isChecked}
                        disabled={
                            existingAutoAddSchedule &&
                            existingAutoAddSchedule.scheduleId !== scheduleId
                        }
                        onChange={() => {
                            setIsChecked(!isChecked);
                            setSchedule({ ...schedule, isAutoAdd: !isChecked });
                        }}
                        label={AUTO_ADD_TEXT}
                    />
                </div>
            </div>
            <Contributions
                contributions={contributions}
                setContributions={setContributions}
            />
            <div className="ContractDistribution-btn-wrap">
                <LinkButton
                    buttonSize="md"
                    label="Cancel"
                    target={getContributorScheduleDetail(
                        contributorId,
                        scheduleId
                    )}
                    variant="default"
                />
                <Button
                    className="save"
                    disabled={isSaving}
                    onClick={saveHandler}
                    variant="primary"
                >
                    Save
                </Button>
            </div>
            <ProgressModal
                headerLabel="Saving in progress"
                isOpen={isSaving}
                modalContent="This action will take couple of minutes so please wait while we save the changes"
                footer="This pop up will close automatically after the process is finished"
                className="SavingModal"
            />
        </div>
    );
};

export default EditScheduleForm;
