import { gql } from "@apollo/client";
import jsreport from "@jsreport/browser-client";
import axios from "axios";
import _ from "lodash";
import { auth } from "../firebase/firebase.utils";
import { setEmailOptions } from "../redux/email/email.actions";
import { store } from "../redux/store";
import client from "../utils/GraphQLClient";
import cleanAxios from "./CleanAxios";
import { TemplateList } from "./TemplateConstants";
import { generateTemplate } from "./graphQLmodifier";

const server = import.meta.env.VITE_APP_REPORTS_SERVER_URL;

jsreport.serverUrl = server;

let Templates;

export function GenerateTemplates() {
  //Required as a part of the transition to Vite.
  //Previous method had the template hash generating before translations loaded, resulting in empty files.
  Templates = TemplateList();
}

export default async function RenderTemplate(
  templateObject,
  bodyshop,
  renderAsHtml = false,
  renderAsExcel = false,
  renderAsText = false,
  notification
) {
  if (window.jsr3) {
    jsreport.serverUrl = "https://reports3.test.imex.online/";
  }
  const jsrAuth = (await axios.post("/utils/jsr")).data;

  jsreport.headers["Authorization"] = jsrAuth;

  //Query assets that match the template name. Must be in format <<templateName>>.query
  let { contextData, useShopSpecificTemplate, shopSpecificFolder } = await fetchContextData(templateObject, jsrAuth);

  const { ignoreCustomMargins } = Templates[templateObject.name];

  let reportRequest = {
    template: {
      name: useShopSpecificTemplate ? `/${bodyshop.imexshopid}/${templateObject.name}` : `/${templateObject.name}`,
      ...(renderAsHtml
        ? {}
        : {
            recipe: "chrome-pdf",
            ...(!ignoreCustomMargins && {
              chrome: {
                marginTop:
                  bodyshop.logo_img_path &&
                  bodyshop.logo_img_path.headerMargin &&
                  bodyshop.logo_img_path.headerMargin > 36
                    ? bodyshop.logo_img_path.headerMargin
                    : "36px",
                marginBottom:
                  bodyshop.logo_img_path &&
                  bodyshop.logo_img_path.footerMargin &&
                  bodyshop.logo_img_path.footerMargin > 50
                    ? bodyshop.logo_img_path.footerMargin
                    : "50px"
              }
            })
          }),
      ...(renderAsExcel ? { recipe: "html-to-xlsx" } : {}),
      ...(renderAsText ? { recipe: "text" } : {})
    },
    data: {
      ...contextData,
      ...templateObject.variables,
      ...templateObject.context,
      headerpath: shopSpecificFolder ? `/${bodyshop.imexshopid}/header.html` : `/GENERIC/header.html`,
      footerpath: shopSpecificFolder ? `/${bodyshop.imexshopid}/footer.html` : `/GENERIC/footer.html`,
      bodyshop: bodyshop,
      filters: templateObject?.filters,
      sorters: templateObject?.sorters,
      offset: bodyshop.timezone, //dayjs().utcOffset(),
      defaultSorters: templateObject?.defaultSorters
    }
  };

  try {
    const render = await jsreport.render(reportRequest);

    if (!renderAsHtml) {
      render.download((Templates[templateObject.name] && Templates[templateObject.name].title) || "");
    } else {
      let pdf;
      if (bodyshop.attach_pdf_to_email) {
        const pdfRequest = _.cloneDeep(reportRequest); //Updates to spread in the header details.
        pdfRequest.template = {
          ...pdfRequest.template,
          ...{
            recipe: "chrome-pdf",
            ...(!ignoreCustomMargins && {
              chrome: {
                marginTop:
                  bodyshop.logo_img_path &&
                  bodyshop.logo_img_path.headerMargin &&
                  bodyshop.logo_img_path.headerMargin > 36
                    ? bodyshop.logo_img_path.headerMargin
                    : "36px",
                marginBottom:
                  bodyshop.logo_img_path &&
                  bodyshop.logo_img_path.footerMargin &&
                  bodyshop.logo_img_path.footerMargin > 50
                    ? bodyshop.logo_img_path.footerMargin
                    : "50px"
              }
            })
          }
        };

        const pdfRender = await jsreport.render(pdfRequest);
        pdf = await pdfRender.toDataURI();
      }
      const html = await render.toString();
      return new Promise((resolve) => {
        resolve({
          pdf,
          filename: Templates[templateObject.name] && Templates[templateObject.name].title,
          html
        });
      });
    }
  } catch (error) {
    notification.error({ title: JSON.stringify(error) });
  }
}

export async function RenderTemplates(templateObjects, bodyshop, renderAsHtml = false, notification) {
  //Query assets that match the template name. Must be in format <<templateName>>.query
  let unsortedTemplatesAndData = [];
  let proms = [];
  const jsrAuth = (await axios.post("/utils/jsr")).data;
  jsreport.headers["Authorization"] = jsrAuth;

  templateObjects.forEach((template) => {
    proms.push(
      (async () => {
        let { contextData, useShopSpecificTemplate, shopSpecificFolder } = await fetchContextData(template, jsrAuth);
        unsortedTemplatesAndData.push({
          templateObject: template,
          contextData,
          useShopSpecificTemplate,
          shopSpecificFolder
        });
      })()
    );
  });
  await Promise.all(proms);

  //Re-order list to follow speedprint.
  // var templateAndData = _.sortBy(unsortedTemplatesAndData, function (item) {
  //   return templateObjects.findIndex(
  //     (template) => template.name === item.templateObject.name
  //   );
  // });
  if (window.jsr3) {
    jsreport.serverUrl = "https://reports3.test.imex.online/";
  }

  unsortedTemplatesAndData.sort(function (a, b) {
    return (
      templateObjects.findIndex((x) => x.name === a.templateObject.name) -
      templateObjects.findIndex((x) => x.name === b.templateObject.name)
    );
  });
  const templateAndData = unsortedTemplatesAndData;

  let rootTemplate = templateAndData.shift();

  let reportRequest = {
    template: {
      name: rootTemplate.useShopSpecificTemplate
        ? `/${bodyshop.imexshopid}/${rootTemplate.templateObject.name}`
        : `/${rootTemplate.templateObject.name}`,
      ...(renderAsHtml
        ? {}
        : {
            recipe: "chrome-pdf",
            chrome: {
              marginTop:
                bodyshop.logo_img_path &&
                bodyshop.logo_img_path.headerMargin &&
                bodyshop.logo_img_path.headerMargin > 36
                  ? bodyshop.logo_img_path.headerMargin
                  : "36px",
              marginBottom:
                bodyshop.logo_img_path &&
                bodyshop.logo_img_path.footerMargin &&
                bodyshop.logo_img_path.footerMargin > 50
                  ? bodyshop.logo_img_path.footerMargin
                  : "50px"
            }
          }),
      pdfOperations: [
        {
          template: {
            name: "/components/Header-Footer",
            recipe: "chrome-pdf",
            engine: "handlebars"
          },
          type: "merge"
        },
        ...templateAndData.map((template) => {
          return {
            template: {
              chrome: {
                marginTop:
                  bodyshop.logo_img_path &&
                  bodyshop.logo_img_path.headerMargin &&
                  bodyshop.logo_img_path.headerMargin > 36
                    ? bodyshop.logo_img_path.headerMargin
                    : "36px",
                marginBottom:
                  bodyshop.logo_img_path &&
                  bodyshop.logo_img_path.footerMargin &&
                  bodyshop.logo_img_path.footerMargin > 50
                    ? bodyshop.logo_img_path.footerMargin
                    : "50px"
              },
              name: template.useShopSpecificTemplate
                ? `/${bodyshop.imexshopid}/${template.templateObject.name}`
                : `/${template.templateObject.name}`,
              ...(renderAsHtml ? {} : { recipe: "chrome-pdf" })
            },
            type: "append"

            // mergeWholeDocument: true,
            // renderForEveryPage: true,
          };
        })
      ]
    },
    data: {
      ...extend(rootTemplate.contextData, ...templateAndData.map((temp) => temp.contextData)),

      // ...rootTemplate.templateObject.variables,
      // ...rootTemplate.templateObject.context,
      headerpath: rootTemplate.shopSpecificFolder ? `/${bodyshop.imexshopid}/header.html` : `/GENERIC/header.html`,
      footerpath: rootTemplate.shopSpecificFolder ? `/${bodyshop.imexshopid}/footer.html` : `/GENERIC/footer.html`,
      bodyshop: bodyshop,
      offset: bodyshop.timezone
    }
  };

  try {
    const render = await jsreport.render(reportRequest);
    if (!renderAsHtml) {
      render.download("Speed Print");
    } else {
      return render.toString();
    }
  } catch (error) {
    notification.error({ title: JSON.stringify(error) });
  }
}

export const GenerateDocument = async (template, messageOptions, sendType, jobid, notification) => {
  const bodyshop = store.getState().user.bodyshop;
  if (sendType === "e") {
    store.dispatch(
      setEmailOptions({
        jobid,
        messageOptions: {
          ...messageOptions,
          to: Array.isArray(messageOptions.to) ? messageOptions.to : [messageOptions.to]
        },
        template
      })
    );
  } else if (sendType === "x") {
    await RenderTemplate(template, bodyshop, false, true, false, notification);
  } else if (sendType === "text") {
    await RenderTemplate(template, bodyshop, false, false, true, notification);
  } else {
    await RenderTemplate(template, bodyshop, false, false, false, notification);
  }
};

export const GenerateDocuments = async (templates, notification) => {
  const bodyshop = store.getState().user.bodyshop;
  await RenderTemplates(templates, bodyshop, false, notification);
};

export const fetchFilterData = async ({ name }) => {
  try {
    const bodyshop = store.getState().user.bodyshop;
    const jsrAuth = (await axios.post("/utils/jsr")).data;
    jsreport.headers["FirebaseAuthorization"] = "Bearer " + (await auth.currentUser.getIdToken());

    const folders = await cleanAxios.get(`${server}/odata/folders`, {
      headers: { Authorization: jsrAuth }
    });
    const shopSpecificFolder = folders.data.value.find((f) => f.name === bodyshop.imexshopid);

    const jsReportFilters = await cleanAxios.get(`${server}/odata/assets?$filter=name eq '${name}.filters'`, {
      headers: { Authorization: jsrAuth }
    });

    let parsedFilterData;
    let useShopSpecificTemplate = false;
    // let shopSpecificTemplate;

    if (shopSpecificFolder) {
      let shopSpecificTemplate = jsReportFilters.data.value.find(
        (f) => f?.folder?.shortid === shopSpecificFolder.shortid
      );
      if (shopSpecificTemplate) {
        useShopSpecificTemplate = true;
        parsedFilterData = atob(shopSpecificTemplate.content);
      }
    }

    if (!parsedFilterData) {
      const generalTemplate = jsReportFilters.data.value.find((f) => !f.folder);
      useShopSpecificTemplate = false;
      if (generalTemplate) parsedFilterData = atob(generalTemplate.content);
    }
    const data = JSON.parse(parsedFilterData);
    return {
      data,
      useShopSpecificTemplate,
      success: true
    };
  } catch {
    return {
      success: false
    };
  }
};

const fetchContextData = async (templateObject, jsrAuth) => {
  const bodyshop = store.getState().user.bodyshop;

  jsreport.headers["FirebaseAuthorization"] = "Bearer " + (await auth.currentUser.getIdToken());

  const folders = await cleanAxios.get(`${server}/odata/folders`, {
    headers: { Authorization: jsrAuth }
  });
  const shopSpecificFolder = folders.data.value.find((f) => f.name === bodyshop.imexshopid);

  const jsReportQueries = await cleanAxios.get(
    `${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`,
    { headers: { Authorization: jsrAuth } }
  );

  let templateQueryToExecute;
  let useShopSpecificTemplate = false;
  // let shopSpecificTemplate;

  if (shopSpecificFolder) {
    let shopSpecificTemplate = jsReportQueries.data.value.find(
      (f) => f?.folder?.shortid === shopSpecificFolder.shortid
    );
    if (shopSpecificTemplate) {
      useShopSpecificTemplate = true;
      templateQueryToExecute = atob(shopSpecificTemplate.content);
    }
  }

  if (!templateQueryToExecute) {
    const generalTemplate = jsReportQueries.data.value.find((f) => !f.folder);
    useShopSpecificTemplate = false;
    templateQueryToExecute = atob(generalTemplate.content);
  }

  // Commented out for future revision debugging
  // console.log('Template Object');
  // console.dir(templateObject);
  // console.log('Unmodified Query');
  // console.dir(templateQueryToExecute);

  const hasFilters = templateObject?.filters?.length > 0;
  const hasSorters = templateObject?.sorters?.length > 0;
  const hasDefaultSorters = templateObject?.defaultSorters?.length > 0;

  // We have no template filters or sorters, so we can just execute the query and return the data
  if (!hasFilters && !hasSorters && !hasDefaultSorters) {
    let contextData = {};
    if (templateQueryToExecute) {
      const { data } = await client.query({
        query: gql(templateQueryToExecute),
        variables: { ...templateObject.variables },
        fetchPolicy: "no-cache"
      });
      contextData = data;
    }
    return {
      contextData,
      useShopSpecificTemplate,
      shopSpecificFolder
    };
  }

  return await generateTemplate(templateQueryToExecute, templateObject, useShopSpecificTemplate, shopSpecificFolder);
};

//export const displayTemplateInWindow = (html) => {
//   try {
//     var newWin = window.open("", "_blank", "toolbar=0,location=0,menubar=0");
//     newWin.document.write(html);

//     setTimeout(function () {
//       newWin.document.close();
//       newWin.focus();
//       newWin.print();
//       newWin.close();
//     }, 500);
//   } catch (error) {
//     console.log("Unable to write to new window.", error);
//   }
// };

// export const displayTemplateInWindowNoprint = (html) => {
//   try {
//     var newWin = window.open("", "_blank", "toolbar=0,location=0,menubar=0");
//     newWin.document.write(html);

//     setTimeout(function () {
//       newWin.document.close();
//       newWin.focus();
//       //newWin.print();
//       //newWin.close();
//     }, 500);
//   } catch (error) {
//     console.log("Unable to write to new window.", error);
//   }
// };

function extend() {
  var result = {},
    obj;

  for (var i = 0; i < arguments.length; i++) {
    obj = arguments[i];
    for (var key in obj) {
      if (Object.prototype.toString.call(obj[key]) === "[object Object]") {
        if (typeof result[key] === "undefined") {
          result[key] = {};
        }
        result[key] = extend(result[key], obj[key]);
      } else {
        result[key] = obj[key];
      }
    }
  }
  return result;
}
