import { AxiosResponse } from "axios";
import { FileTemplate } from "core/models/FileTemplate";
import saveAs from "file-saver";
import React from "react";
import { useTranslation } from "react-i18next";
import { finalize, Observable } from "rxjs";
import { FileTemplateParams } from "./FileTemplate";

enum FILE_TEMPLATE_ENUM {
  UPDATE_ALL_FILE_TEMPLATE,
  UPDATE_SINGLE,
  UPDATE_LIST,
  LOAD_FILE,
  UPDATE_FILE_URL,
}

interface FileTemplateState {
  fileTemplates?: FileTemplate[];
  currentfileTemplate?: FileTemplate;
  pdfBlobUrl?: string;
}

interface FileTemplateAction {
  type: FILE_TEMPLATE_ENUM;
  data: FileTemplateState;
}

function fileTemplateReducer(
  state: FileTemplateState,
  action: FileTemplateAction
): FileTemplateState {
  switch (action.type) {
    case FILE_TEMPLATE_ENUM.UPDATE_ALL_FILE_TEMPLATE:
      return {
        fileTemplates: [...action.data.fileTemplates],
        currentfileTemplate: { ...action.data.currentfileTemplate },
        pdfBlobUrl: action.data.pdfBlobUrl,
      };
    case FILE_TEMPLATE_ENUM.UPDATE_LIST:
      return {
        ...state,
        fileTemplates: [...action.data.fileTemplates],
      };
    case FILE_TEMPLATE_ENUM.UPDATE_SINGLE:
      return {
        ...state,
        currentfileTemplate: { ...action.data.currentfileTemplate },
      };
    case FILE_TEMPLATE_ENUM.LOAD_FILE:
      return {
        ...state,
        pdfBlobUrl: action.data.pdfBlobUrl,
      };
    case FILE_TEMPLATE_ENUM.UPDATE_FILE_URL:
      return {
        ...state,
        pdfBlobUrl: action.data.pdfBlobUrl,
        currentfileTemplate: { ...action.data.currentfileTemplate },
      };
    default:
      return { ...state };
  }
}

export default function useFileTemplateHook(
  getListFileTemplates: () => Observable<FileTemplate[]>,
  previewFileTemplate: (params: FileTemplateParams) => Observable<any>,
  downloadFileTemplatePdf: (params: FileTemplateParams) => Observable<any>,
  downloadFileTemplateOriginal: (params: FileTemplateParams) => Observable<any>,
  saveFileTemplate?: (fileTemplate: FileTemplate) => void,
  dataParams?: any
) {
  const [translate] = useTranslation();
  const [loadingPdf, setLoadingPdf] = React.useState(false);

  const [
    { fileTemplates, currentfileTemplate, pdfBlobUrl },
    dispatchFileTemplate,
  ] = React.useReducer(fileTemplateReducer, {
    fileTemplates: [],
    currentfileTemplate: new FileTemplate(),
    pdfBlobUrl: "",
  });

  const handlePreviewFileTemplate = React.useCallback(() => {
    const template = { ...currentfileTemplate };
    const queryParams = dataParams ? dataParams : undefined;
    setLoadingPdf(true);
    previewFileTemplate({
      queryParams,
      template,
    })
      .pipe(finalize(() => setLoadingPdf(false)))
      .subscribe({
        next: (response: AxiosResponse<any>) => {
          const file = new Blob([response.data], {
            type: "application/pdf",
          });
          const fileURL = URL.createObjectURL(file);
          dispatchFileTemplate({
            type: FILE_TEMPLATE_ENUM.LOAD_FILE,
            data: {
              pdfBlobUrl: fileURL,
            },
          });
        },
      });
  }, [currentfileTemplate, dataParams, previewFileTemplate]);

  const handleDownloadFileTemplate = React.useCallback(() => {
    const template = { ...currentfileTemplate };
    const queryParams = dataParams ? dataParams : undefined;
    downloadFileTemplatePdf({
      template,
      queryParams,
    }).subscribe({
      next: (response: AxiosResponse<any>) => {
        const fileName = response.headers["content-disposition"]
          .split(";")
          .find((n: any) => n.includes("filename="))
          .replace("filename=", "")
          .replace(/"/gi, "")
          .trim();
        const url = window.URL.createObjectURL(
          new Blob([response.data], {
            type: "application/octet-stream",
          })
        );
        saveAs(url, fileName);
      },
    });
  }, [currentfileTemplate, dataParams, downloadFileTemplatePdf]);

  const handleDownloadFileTemplateOriginal = React.useCallback(() => {
    const template = { ...currentfileTemplate };
    const queryParams = dataParams ? dataParams : undefined;
    downloadFileTemplateOriginal({
      template,
      queryParams,
    }).subscribe({
      next: (response: AxiosResponse<any>) => {
        const fileName = response.headers["content-disposition"]
          .split(";")
          .find((n: any) => n.includes("filename="))
          .replace("filename=", "")
          .replace(/"/gi, "")
          .trim();
        const url = window.URL.createObjectURL(
          new Blob([response.data], {
            type: "application/octet-stream",
          })
        );
        saveAs(url, fileName);
      },
    });
  }, [currentfileTemplate, dataParams, downloadFileTemplateOriginal]);

  const handleChangeFileTemplateInputValue = React.useCallback(
    (index: number) => (value: string) => {
      const fileTemplate = { ...currentfileTemplate };
      fileTemplate.inputs[index].fieldValue = value;
      dispatchFileTemplate({
        type: FILE_TEMPLATE_ENUM.UPDATE_SINGLE,
        data: {
          currentfileTemplate: fileTemplate,
        },
      });
    },
    [currentfileTemplate]
  );

  const handleChangeFileTemplateName = React.useCallback(
    (value: string) => {
      const fileTemplate = { ...currentfileTemplate };
      fileTemplate.name = value;
      dispatchFileTemplate({
        type: FILE_TEMPLATE_ENUM.UPDATE_SINGLE,
        data: {
          currentfileTemplate: fileTemplate,
        },
      });
    },
    [currentfileTemplate]
  );

  const handleChangeFileTemplate = React.useCallback(
    (event: any) => {
      const fileTemplateId = Number(event.key);
      const template = fileTemplates.filter(
        (fileTemplate: FileTemplate) => fileTemplate.id === fileTemplateId
      )[0];
      setLoadingPdf(true);
      const queryParams = dataParams ? dataParams : undefined;
      previewFileTemplate({
        queryParams,
        template,
      })
        .pipe(finalize(() => setLoadingPdf(false)))
        .subscribe({
          next: (response: AxiosResponse<any>) => {
            const file = new Blob([response.data], {
              type: "application/pdf",
            });
            const fileURL = URL.createObjectURL(file);
            dispatchFileTemplate({
              type: FILE_TEMPLATE_ENUM.UPDATE_FILE_URL,
              data: {
                currentfileTemplate: template,
                pdfBlobUrl: fileURL,
              },
            });
          },
        });
    },
    [dataParams, fileTemplates, previewFileTemplate]
  );

  const handleSaveFileTemplate = React.useCallback(() => {
    const fileTemplate = { ...currentfileTemplate };
    saveFileTemplate(fileTemplate);
  }, [currentfileTemplate, saveFileTemplate]);

  React.useEffect(() => {
    const subcription = getListFileTemplates().subscribe({
      next: (res: FileTemplate[]) => {
        if (res && res.length > 0) {
          const fileTemplates = res;
          const currentfileTemplate = res[0];
          setLoadingPdf(true);
          dispatchFileTemplate({
            type: FILE_TEMPLATE_ENUM.UPDATE_ALL_FILE_TEMPLATE,
            data: {
              fileTemplates,
              currentfileTemplate,
            },
          });
          previewFileTemplate({
            queryParams: dataParams,
            template: currentfileTemplate,
          })
            .pipe(finalize(() => setLoadingPdf(false)))
            .subscribe({
              next: (response: AxiosResponse<any>) => {
                const file = new Blob([response.data], {
                  type: "application/pdf",
                });
                const fileURL = URL.createObjectURL(file);
                dispatchFileTemplate({
                  type: FILE_TEMPLATE_ENUM.LOAD_FILE,
                  data: {
                    pdfBlobUrl: fileURL,
                  },
                });
              },
            });
        }
      },
    });
    return () => {
      subcription.unsubscribe();
    };
  }, [dataParams, getListFileTemplates, previewFileTemplate]);

  return {
    currentfileTemplate,
    fileTemplates,
    pdfBlobUrl,
    loadingPdf,
    translate,
    handleChangeFileTemplateInputValue,
    handleChangeFileTemplateName,
    handleChangeFileTemplate,
    handlePreviewFileTemplate,
    handleDownloadFileTemplate,
    handleDownloadFileTemplateOriginal,
    handleSaveFileTemplate,
  };
}
