/**
 * @file pdfViewerInjections.tsx - DOM injection utilities that programmatically add custom UI elements to the Syncfusion PDF viewer's toolbar and annotation toolbar.
 *
 * Injected elements include:
 * - A "Save Document" button in the main toolbar
 * - A custom stamp annotation dropdown in the annotation toolbar
 * - A "Scan Insert" dropdown for RWP Companion integration (Windows only)
 * - An "Image Cleanup" button for RWP Companion integration (Windows only)
 *
 * Each injection feature creates DOM elements, renders React components into them via createRoot, and places them at specific locations in the Syncfusion toolbar DOM.
 * Corresponding removal functions clean up injected elements when no longer needed.
 */

import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap';
import { createRoot } from 'react-dom/client';
import { Icon } from '../components/Icon.tsx';
import { TooltipComponent } from '@syncfusion/ej2-react-popups';
import {
  DropDownButtonComponent,
  type MenuEventArgs,
} from '@syncfusion/ej2-react-splitbuttons';
import {
  addCustomStampAnnotation,
  addSignatureAnnotation,
  type CustomStampAnnotation,
} from './stampAnnotations.ts';
import type { PdfViewerComponent } from '@syncfusion/ej2-react-pdfviewer';
import type { RefObject } from 'react';
import type { customStampAnnotations } from './stampAnnotations.ts';
import type { ScanInsertMode } from '../types/companionTool.ts';
import { type Document } from '../api/document.ts';
import type { RetrieveAndSaveDocumentProps } from './retrieveAndSaveDocument.ts';
import i18next from 'i18next';

/** Shared props required by all PDF viewer injection functions. */
export interface PdfViewerInjectionsProps {
  // Related to Syncfusion PDF Viewer
  pdfViewerRef: RefObject<PdfViewerComponent>;
  isDevice: boolean;
  isWindows: boolean;
  signatureAnnotation: CustomStampAnnotation;
  username: string;

  hasEditPermission: boolean;

  // Related to saving documents
  retrieveAndSaveDocumentProps: RetrieveAndSaveDocumentProps;
  saveDocument: (
    props: RetrieveAndSaveDocumentProps,
    newDocumentsArray?: Document[]
  ) => void;

  // Modal state properties
  showScanInsertModal: (mode: ScanInsertMode) => void;
  showImageCleanupModal: () => void;
}

/**
 * Injects buttons/dropdown buttons into the Syncfusion PDF Viewer main and annotation toolbars.
 *
 * @param props PDF Viewer injections props
 */
export const injectToolbarButtons = (props: PdfViewerInjectionsProps) => {
  const {
    pdfViewerRef,
    isDevice,
    isWindows,
    hasEditPermission,
    retrieveAndSaveDocumentProps,
    saveDocument,
    signatureAnnotation,
    username,
    showScanInsertModal,
    showImageCleanupModal,
  } = props;

  injectSaveDocumentButton(
    hasEditPermission,
    retrieveAndSaveDocumentProps,
    saveDocument
  );
  injectCustomStampDropdown(
    isDevice,
    hasEditPermission,
    pdfViewerRef,
    signatureAnnotation,
    username
  );
  injectScanInsertDropdown(
    isDevice,
    isWindows,
    hasEditPermission,
    showScanInsertModal
  );
  injectImageCleanupButton(
    isDevice,
    isWindows,
    hasEditPermission,
    showImageCleanupModal
  );
};

/**
 * Removes injected buttons/dropdown buttons from the Syncfusion PDF Viewer main and annotation toolbars.
 */
export const removeToolbarButtons = () => {
  removeSaveDocumentButton();
  removeCustomStampDropdown();
  removeScanInsertDropdown();
  removeImageCleanupButton();
};

// CSS selector and element IDs for the Save Document button injection point
const saveDocumentToolbarSelector =
  '#pdf-viewer_toolbarItemsContainer > .e-toolbar-right';
const saveDocumentSeparatorId = 'save-document-separator';
const saveDocumentButtonId = 'save-document-button';

/**
 * Returns whether the "Save Document" button and associated separator exist in the Syncfusion PDF Viewer main toolbar.
 *
 * @returns Whether the "Save Document" button elements exist
 */
export const saveDocumentButtonExists = () => {
  const toolbar = document.querySelector(saveDocumentToolbarSelector);
  if (!toolbar) {
    return false;
  }
  return Boolean(
    toolbar.querySelector('#' + saveDocumentSeparatorId) &&
      toolbar.querySelector('#' + saveDocumentButtonId)
  );
};

/**
 * Removes the existing "Save Document" button and associated separator in the Syncfusion PDF Viewer main toolbar.
 */
export const removeSaveDocumentButton = () => {
  const toolbar = document.querySelector(saveDocumentToolbarSelector);
  if (toolbar) {
    const existingSeparator = toolbar.querySelector(
      '#' + saveDocumentSeparatorId
    );
    const existingButton = toolbar.querySelector('#' + saveDocumentButtonId);
    if (existingSeparator && existingButton) {
      toolbar.removeChild(existingSeparator);
      toolbar.removeChild(existingButton);
    }
  }
};

/**
 * Creates and injects a "Save Document" button and associated separator in the Syncfusion PDF Viewer main toolbar.
 *
 * @param hasPermission Whether the user has permission to use the button
 * @param retrieveAndSaveDocumentProps Retrieve and save document props
 * @param saveDocument Function that saves the document
 */
export const injectSaveDocumentButton = (
  hasPermission: boolean,
  retrieveAndSaveDocumentProps: RetrieveAndSaveDocumentProps,
  saveDocument: (props: RetrieveAndSaveDocumentProps) => void
) => {
  const tKey =
    'utils.pdf_viewer_injections.functions.inject_save_document_button';

  const toolbar = document.querySelector(saveDocumentToolbarSelector);
  if (toolbar) {
    removeSaveDocumentButton();

    if (hasPermission) {
      const separator = document.createElement('div');
      separator.id = saveDocumentSeparatorId;
      separator.className =
        'e-toolbar-item e-pv-navigation-separator-container e-separator';
      toolbar.appendChild(separator);

      const button = document.createElement('div');
      button.id = saveDocumentButtonId;
      button.className =
        'e-toolbar-item e-pv-annotation-container e-popup-text';
      toolbar.appendChild(button);

      const root = createRoot(button);
      root.render(
        <OverlayTrigger
          placement={'top'}
          overlay={
            <Tooltip className={'position-fixed'}>
              {i18next.t(tKey + '.tooltip')}
            </Tooltip>
          }
        >
          <Button
            variant={'success'}
            size={'sm'}
            className={'pb-1'}
            onClick={() => saveDocument(retrieveAndSaveDocumentProps)}
          >
            <div className={'d-flex justify-content-center align-items-center'}>
              <Icon iconName={'Floppy'} size={18} />
              <span className={'ms-2'}>{i18next.t(tKey + '.button_text')}</span>
            </div>
          </Button>
        </OverlayTrigger>
      );
    }
  }
};

// CSS selector and element IDs for the custom stamp dropdown injection point (annotation toolbar)
const customStampButtonToolbarSelector =
  '#pdf-viewer_annotation_toolbar > .e-toolbar-items > .e-toolbar-left';
const freeTextEditContainerSelector =
  '#pdf-viewer_annotation_freeTextEditContainer';
const customStampButtonSeparatorId = 'custom-stamp-button-separator';
const customStampButtonContainerId = 'custom-stamp-button-container';

/**
 * Returns whether the custom stamp annotation dropdown and associated separator exist in the Syncfusion PDF Viewer annotation toolbar.
 *
 * @returns Whether the custom stamp annotation dropdown elements exist
 */
export const customStampDropdownExists = () => {
  const toolbar = document.querySelector(customStampButtonToolbarSelector);
  if (!toolbar) {
    return false;
  }
  return Boolean(
    toolbar.querySelector('#' + customStampButtonSeparatorId) &&
      toolbar.querySelector('#' + customStampButtonContainerId)
  );
};

/**
 * Removes the existing custom stamp annotation dropdown button and associated separator in the Syncfusion PDF Viewer annotation toolbar.
 */
export const removeCustomStampDropdown = () => {
  const toolbar = document.querySelector(customStampButtonToolbarSelector);
  if (toolbar) {
    const existingSeparator = toolbar.querySelector(
      '#' + customStampButtonSeparatorId
    );
    const existingContainer = toolbar.querySelector(
      '#' + customStampButtonContainerId
    );
    if (existingSeparator && existingContainer) {
      toolbar.removeChild(existingSeparator);
      toolbar.removeChild(existingContainer);
    }
  }
};

/**
 * Creates and injects a custom stamp annotation dropdown button and associated separator in the Syncfusion PDF Viewer annotation toolbar.
 *
 * @param isDevice Whether the user's device is a mobile device
 * @param hasPermission Whether the user has permission to use the button
 * @param pdfViewerRef RefObject of Syncfusion PDF Viewer component
 * @param signatureAnnotation Signature annotation object
 * @param username Username of current user (stamp annotation author)
 */
export const injectCustomStampDropdown = (
  isDevice: boolean,
  hasPermission: boolean,
  pdfViewerRef: RefObject<PdfViewerComponent>,
  signatureAnnotation: CustomStampAnnotation,
  username: string
) => {
  const tKey =
    'utils.pdf_viewer_injections.functions.inject_custom_stamp_dropdown';

  const textAnnotationButton = document.querySelector(
    freeTextEditContainerSelector
  );
  if (textAnnotationButton) {
    removeCustomStampDropdown();

    if (!isDevice && hasPermission) {
      const separator = document.createElement('div');
      separator.id = customStampButtonSeparatorId;
      separator.className =
        'e-toolbar-item e-pv-freetext-separator-container e-separator';
      textAnnotationButton.after(separator);

      const container = document.createElement('div');
      container.id = customStampButtonContainerId;
      container.className =
        'e-toolbar-item e-tbtn-align e-pv-annotation-freeTextEdit-container e-popup-text';
      separator.after(container);

      const root = createRoot(container);
      root.render(
        <TooltipComponent
          content={i18next.t(tKey + '.tooltip')}
          opensOn={'Hover'}
        >
          <DropDownButtonComponent
            items={[
              {
                text: 'Unreadable',
                id: 'Unreadable',
              },
              {
                text: 'Check Copy',
                id: 'CheckCopy',
              },
              {
                text: 'Receipt Only',
                id: 'ReceiptOnly',
              },
              {
                text: 'No Return Address',
                id: 'NoReturnAddress',
              },
              {
                text: 'Blank Page',
                id: 'BlankPage',
              },
              {
                separator: true,
              },
              {
                text: i18next.t(tKey + '.dropdown_items.signature'),
                id: 'Signature',
              },
            ]}
            iconCss={'e-pv-stamp-icon e-pv-icon'}
            cssClass={'e-flat'}
            select={(args: MenuEventArgs) => {
              if (args.item.id === 'Signature') {
                addSignatureAnnotation(
                  pdfViewerRef,
                  signatureAnnotation,
                  username
                );
              } else {
                addCustomStampAnnotation(
                  pdfViewerRef,
                  args.item.id as keyof typeof customStampAnnotations,
                  username
                );
              }
            }}
          />
        </TooltipComponent>
      );
    }
  }
};

// CSS selector and element IDs for the Scan Insert dropdown injection point
const scanInsertDropdownToolbarSelector =
  '#pdf-viewer_toolbarItemsContainer > .e-toolbar-left';
const scanInsertSeparatorId = 'scan-insert-separator';
const scanInsertButtonId = 'scan-insert-button';

/**
 * Returns whether the "Scan Insert" dropdown button and associated separator exist in the Syncfusion PDF Viewer main toolbar.
 *
 * @returns Whether the "Scan Insert" dropdown elements exist
 */
export const scanInsertDropdownExists = () => {
  const toolbar = document.querySelector(scanInsertDropdownToolbarSelector);
  if (!toolbar) {
    return false;
  }
  return Boolean(
    toolbar.querySelector('#' + scanInsertSeparatorId) &&
      toolbar.querySelector('#' + scanInsertButtonId)
  );
};

/**
 * Removes the existing "Scan Insert" dropdown button and associated separator in the Syncfusion PDF Viewer main toolbar.
 */
export const removeScanInsertDropdown = () => {
  const toolbar = document.querySelector(scanInsertDropdownToolbarSelector);
  if (toolbar) {
    const existingSeparator = toolbar.querySelector(
      '#' + scanInsertSeparatorId
    );
    const existingButton = toolbar.querySelector('#' + scanInsertButtonId);
    if (existingSeparator && existingButton) {
      toolbar.removeChild(existingSeparator);
      toolbar.removeChild(existingButton);
    }
  }
};

/**
 * Creates and injects a "Scan Insert" dropdown button and associated separator in the Syncfusion PDF Viewer main toolbar.
 *
 * @param isDevice Whether the user's device is a mobile device
 * @param isWindows Whether the user's device runs Windows
 * @param hasPermission Whether the user has permission to use the button
 * @param showModal Function to show associated modal component
 */
export const injectScanInsertDropdown = (
  isDevice: boolean,
  isWindows: boolean,
  hasPermission: boolean,
  showModal: (mode: ScanInsertMode) => void
) => {
  const tKey =
    'utils.pdf_viewer_injections.functions.inject_scan_insert_dropdown';

  const toolbar = document.querySelector(scanInsertDropdownToolbarSelector);
  if (toolbar) {
    removeScanInsertDropdown();

    if (
      !isDevice &&
      isWindows &&
      hasPermission &&
      String(window.__APP_CONFIG__?.ENABLE_RWP_COMPANION).toLowerCase() ===
        'true'
    ) {
      const separator = document.createElement('div');
      separator.id = scanInsertSeparatorId;
      separator.className =
        'e-toolbar-item e-pv-navigation-separator-container e-separator';
      toolbar.appendChild(separator);

      const button = document.createElement('div');
      button.id = scanInsertButtonId;
      button.className =
        'e-toolbar-item e-pv-annotation-container e-popup-text';
      toolbar.appendChild(button);

      const root = createRoot(button);
      root.render(
        <TooltipComponent
          content={i18next.t(tKey + '.tooltip')}
          opensOn={'Hover'}
        >
          <DropDownButtonComponent
            items={[
              {
                text: i18next.t(tKey + '.dropdown_items.before'),
                id: 'before',
              },
              {
                text: i18next.t(tKey + '.dropdown_items.after'),
                id: 'after',
              },
              {
                text: i18next.t(tKey + '.dropdown_items.end'),
                id: 'end',
              },
            ]}
            iconCss={'e-icons e-break-page'}
            cssClass={'e-flat'}
            select={(args: MenuEventArgs) => {
              showModal(args.item.id as ScanInsertMode);
            }}
          />
        </TooltipComponent>
      );
    }
  }
};

// CSS selector and element IDs for the Image Cleanup button injection point
const imageCleanupButtonToolbarSelector =
  '#pdf-viewer_toolbarItemsContainer > .e-toolbar-left';
const imageCleanupSeparatorId = 'image-cleanup-separator';
const imageCleanupButtonId = 'image-cleanup-button';

/**
 * Returns whether the "Image Cleanup" dropdown button and associated separator exist in the Syncfusion PDF Viewer main toolbar.
 *
 * @returns Whether the "Image Cleanup" dropdown elements exist
 */
export const imageCleanupButtonExists = () => {
  const toolbar = document.querySelector(imageCleanupButtonToolbarSelector);
  if (!toolbar) {
    return false;
  }
  return Boolean(
    toolbar.querySelector('#' + imageCleanupSeparatorId) &&
      toolbar.querySelector('#' + imageCleanupButtonId)
  );
};

/**
 * Removes the existing "Image Cleanup" button and associated separator in the Syncfusion PDF Viewer main toolbar.
 */
export const removeImageCleanupButton = () => {
  const toolbar = document.querySelector(imageCleanupButtonToolbarSelector);
  if (toolbar) {
    const existingSeparator = toolbar.querySelector(
      '#' + imageCleanupSeparatorId
    );
    const existingButton = toolbar.querySelector('#' + imageCleanupButtonId);
    if (existingSeparator && existingButton) {
      toolbar.removeChild(existingSeparator);
      toolbar.removeChild(existingButton);
    }
  }
};

/**
 * Creates and injects an "Image Cleanup" button and associated separator in the Syncfusion PDF Viewer main toolbar.
 *
 * @param isDevice Whether the user's device is a mobile device
 * @param isWindows Whether the user's device runs Windows
 * @param hasPermission Whether the user has permission to use the button
 * @param showModal Function to show associated modal component
 */
export const injectImageCleanupButton = (
  isDevice: boolean,
  isWindows: boolean,
  hasPermission: boolean,
  showModal: () => void
) => {
  const tKey =
    'utils.pdf_viewer_injections.functions.inject_image_cleanup_button';

  const toolbar = document.querySelector(imageCleanupButtonToolbarSelector);
  if (toolbar) {
    removeImageCleanupButton();

    if (
      !isDevice &&
      isWindows &&
      hasPermission &&
      String(window.__APP_CONFIG__?.ENABLE_RWP_COMPANION).toLowerCase() ===
        'true'
    ) {
      const separator = document.createElement('div');
      separator.id = imageCleanupSeparatorId;
      separator.className =
        'e-toolbar-item e-pv-navigation-separator-container e-separator';
      toolbar.appendChild(separator);

      const button = document.createElement('div');
      button.id = imageCleanupButtonId;
      button.className =
        'e-toolbar-item e-pv-annotation-container e-popup-text';
      toolbar.appendChild(button);

      const root = createRoot(button);
      root.render(
        <OverlayTrigger
          placement={'top'}
          overlay={
            <Tooltip className={'position-fixed'}>
              {i18next.t(tKey + '.tooltip')}
            </Tooltip>
          }
        >
          <Button
            variant={'outline-secondary'}
            size={'sm'}
            className={'pb-1'}
            onClick={showModal}
          >
            <div className={'d-flex justify-content-center align-items-center'}>
              <Icon iconName={'Magic'} />
            </div>
          </Button>
        </OverlayTrigger>
      );
    }
  }
};
