/**
 * @file retrieveAndSaveDocument.ts - Functions for retrieving document content from the IWS5 API and saving edited documents back.
 * Both functions manage loading states and display toast notifications for user feedback.
 */

import {
  type Document,
  getDocumentContent,
  updateDocumentContent,
} from '../api/document.ts';
import type { Dispatch, RefObject, SetStateAction } from 'react';
import type { PdfViewerComponent } from '@syncfusion/ej2-react-pdfviewer';
import { toast } from 'react-toastify';
import type { Process } from '../api/process.ts';
import type { WorkItem } from '../api/workItem.ts';
import i18next from 'i18next';
import type { FetchError } from './fetchHelper.ts';

/** Shared props required by the retrieve and save document functions. */
export interface RetrieveAndSaveDocumentProps {
  // Work item properties
  process: Process | undefined;
  workItem: WorkItem | undefined;
  documents: Document[];
  setDocuments: (documents: Document[]) => void;

  // Related to Syncfusion PDF Viewer
  pdfViewerRef: RefObject<PdfViewerComponent>;
  hasLoadedOnce: boolean;
  setForceViewerLoad: Dispatch<SetStateAction<number>>;

  // Selected document properties
  selectedDocumentId: number | undefined;
  selectedDocumentContent: string | undefined;
  setSelectedDocumentContent: (content: string | undefined) => void;
  setSelectedDocumentContentHasChanged: (changed: boolean) => void;
  setOldSelectedDocumentId: (documentId: number) => void;

  // Other view state properties
  setDocumentIsLoading: (loading: boolean) => void;
  setDocumentActionButtonsDisabled: (disabled: boolean) => void;
  setDeleteDocumentButtonDisabled: (disabled: boolean) => void;
  setJustSavedDocument: (justSaved: boolean) => void;
}

/**
 * Retrieves the content of a document by its ID.
 *
 * @param props Retrieve and save document props
 * @param documentId ID of document to retrieve
 */
export const retrieveDocument = async (
  props: RetrieveAndSaveDocumentProps,
  documentId: number
) => {
  const {
    pdfViewerRef,
    documents,
    selectedDocumentContent,
    setSelectedDocumentContent,
    hasLoadedOnce,
    setForceViewerLoad,
    setDocumentIsLoading,
    setOldSelectedDocumentId,
  } = props;

  const found = documents.find(
    (_document) => _document.documentId === documentId
  );

  if (found) {
    if (hasLoadedOnce) {
      pdfViewerRef.current?.unload();
    }

    setDocumentIsLoading(true);

    // Retrieve document content
    getDocumentContent(documentId)
      .then((content) => {
        if (content === selectedDocumentContent) {
          setForceViewerLoad((prev) => prev + 1);
        }
        setSelectedDocumentContent(content);
      })
      .catch((error: FetchError) => {
        toast.error(error.message);
      });

    setDocumentIsLoading(false);
  } else {
    setSelectedDocumentContent(undefined);
  }
  setOldSelectedDocumentId(documentId);
};

/**
 * Saves the currently selected document and updates its content.
 *
 * @param props Retrieve and save document props
 * @param newDocumentsArray New documents array
 */
export const saveDocument = async (
  props: RetrieveAndSaveDocumentProps,
  newDocumentsArray?: Document[]
) => {
  const {
    pdfViewerRef,
    documents,
    setDocuments,
    setSelectedDocumentContent,
    setSelectedDocumentContentHasChanged,
    selectedDocumentId,
    process,
    workItem,
    setDocumentActionButtonsDisabled,
    setDeleteDocumentButtonDisabled,
    setJustSavedDocument,
  } = props;

  const tKey = 'utils.retrieve_and_save_document.functions.save_document';

  if (selectedDocumentId) {
    const document = documents.find(
      (_document) => _document.documentId === selectedDocumentId
    );

    // Get PDF viewer document as blob
    pdfViewerRef.current?.saveAsBlob().then((blobData) => {
      const reader = new FileReader();

      reader.onload = () => {
        const result = reader.result as string;
        const base64 = result.split(',')[1];

        setDocumentActionButtonsDisabled(true);
        setDeleteDocumentButtonDisabled(true);
        toast.info(`${i18next.t(tKey + '.info')}: ` + document?.documentName, {
          toastId: 'saving-document-' + document?.documentId,
          autoClose: false,
        });

        updateDocumentContent(
          process?.id as number,
          workItem?.workItemReferenceId as number,
          document?.documentId as number,
          base64
        )
          .then((newDocument) => {
            const docs = (newDocumentsArray as Document[]) || documents;
            setDocuments(
              docs.map((_document) => {
                if (_document.documentId === document?.documentId) {
                  _document.documentSize = newDocument.documentSize;
                  _document.userName = newDocument.userName;
                  _document.lastModified = newDocument.lastModified;
                }
                return _document;
              })
            );

            setSelectedDocumentContent(base64);
            setJustSavedDocument(true);
            setSelectedDocumentContentHasChanged(false);

            toast.success(
              `${i18next.t(tKey + '.success')}: ` + document?.documentName
            );
          })
          .catch(() => {
            toast.error(
              `${i18next.t(tKey + '.errors.failed_to_save')}: ` +
                document?.documentName
            );
          })
          .finally(() => {
            setDocumentActionButtonsDisabled(false);
            setDeleteDocumentButtonDisabled(false);
            toast.dismiss('saving-document-' + document?.documentId);
          });
      };

      reader.onerror = () => {
        toast.error(
          `${i18next.t(tKey + '.errors.failed_to_read')}: ` +
            document?.documentName
        );
      };

      reader.readAsDataURL(blobData);
    });
  }
};
