import { useMutation } from "@apollo/client/react";
import { Form, Modal } from "antd";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries.js";
import { INSERT_NEW_NOTE, UPDATE_NOTE } from "../../graphql/notes.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectNoteUpsert } from "../../redux/modals/modals.selectors";
import { selectCurrentUser } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import NoteUpsertModalComponent from "./note-upsert-modal.component";

const mapStateToProps = createStructuredSelector({
  currentUser: selectCurrentUser,
  noteUpsertModal: selectNoteUpsert
});
const mapDispatchToProps = (dispatch) => ({
  toggleModalVisible: () => dispatch(toggleModalVisible("noteUpsert")),
  insertAuditTrail: ({ jobid, operation, type }) =>
    dispatch(
      insertAuditTrail({
        jobid,
        operation,
        type
      })
    )
});

export function NoteUpsertModalContainer({ currentUser, noteUpsertModal, toggleModalVisible, insertAuditTrail }) {
  const { t } = useTranslation();
  const [insertNote] = useMutation(INSERT_NEW_NOTE);
  const [updateNote] = useMutation(UPDATE_NOTE);
  const notification = useNotification();

  const { open, context, actions } = noteUpsertModal;
  const { jobId, existingNote, text } = context;
  const { refetch } = actions;

  const [form] = Form.useForm();
  useEffect(() => {
    //Required to prevent infinite looping.
    if (existingNote && open) {
      form.setFieldsValue(existingNote);
    } else if (!existingNote && open) {
      form.resetFields();

      if (text) {
        form.setFieldValue("text", text);
      }
    }
  }, [existingNote, form, open, text]);

  const handleFinish = async (formValues) => {
    const { relatedros, ...values } = formValues;

    if (existingNote) {
      logImEXEvent("job_note_update");

      updateNote({
        variables: {
          noteId: existingNote.id,
          note: values
        },
        refetchQueries: ["GET_JOB_BY_PK", "QUERY_JOB_CARD_DETAILS", "QUERY_PARTS_QUEUE_CARD_DETAILS"]
      }).then(() => {
        notification.success({
          title: t("notes.successes.updated")
        });
        insertAuditTrail({
          jobid: context.jobId,
          operation: AuditTrailMapping.jobnoteupdated(),
          type: "jobnoteupdated"
        });
      });
      if (refetch) refetch();
      toggleModalVisible();
    } else {
      logImEXEvent("job_note_insert");
      const AdditionalNoteInserts = relatedros ? Object.keys(relatedros).filter((key) => relatedros[key]) : [];

      await insertNote({
        variables: {
          noteInput: [{ ...values, jobid: jobId, created_by: currentUser.email }]
        },
        update(cache, { data: { updateNote: updatedNote } }) {
          try {
            const existingJob = cache.readQuery({
              query: GET_JOB_BY_PK,
              variables: { id: jobId }
            });

            if (existingJob) {
              cache.writeQuery({
                query: GET_JOB_BY_PK,
                variables: { id: jobId },
                data: {
                  ...existingJob,
                  job: {
                    ...existingJob.job,
                    notes: updatedNote.pinned
                      ? [updatedNote, ...existingJob.job.notes]
                      : existingJob.job.notes.filter((n) => n.id !== updatedNote.id)
                  }
                }
              });
            }
          } catch {
            // Cache miss is okay, query hasn't been executed yet
            console.log("Cache miss for GET_JOB_BY_PK");
          }
        },
        refetchQueries: ["QUERY_NOTES_BY_JOB_PK"]
      });

      if (AdditionalNoteInserts.length > 0) {
        //Insert the others.
        AdditionalNoteInserts.forEach(async (newJobId) => {
          await insertNote({
            variables: {
              noteInput: [{ ...values, jobid: newJobId, created_by: currentUser.email }]
            }
          });
          insertAuditTrail({
            jobid: newJobId,
            operation: AuditTrailMapping.jobnoteadded(),
            type: "jobnoteadded"
          });
        });
      }

      if (refetch) refetch();
      form.resetFields();
      toggleModalVisible();
      notification.success({
        title: t("notes.successes.create")
      });
      insertAuditTrail({
        jobid: context.jobId,
        operation: AuditTrailMapping.jobnoteadded(),
        type: "jobnoteadded"
      });
    }
  };

  return (
    <Modal
      title={existingNote ? t("notes.actions.edit") : t("notes.actions.new")}
      open={open}
      okText={t("general.actions.save")}
      onOk={() => {
        form.submit();
      }}
      onCancel={() => {
        toggleModalVisible();
      }}
      destroyOnHidden
    >
      <Form form={form} onFinish={handleFinish} layout="vertical">
        <NoteUpsertModalComponent form={form} />
      </Form>
    </Modal>
  );
}

export default connect(mapStateToProps, mapDispatchToProps)(NoteUpsertModalContainer);
