import { HotelItinerary } from '@hotel-lib/itinerary';
import { TrainItinerary } from '@train-lib/itinerary';
import { InvoiceValidation } from '@commerce-lib/trains/invoice_validations';
import { xmlEu } from '@fixtures/commerce/xml/xml_eu';
import { Timeouts, Utility } from '@utility-lib/index';
import { CommerceShared } from '@commerce-lib/shared';
import { stagingUsers } from '@fixtures/staging-users';
import { HttpStatusCodes } from '@support-base/status_code';
import { FlightItinerary } from '@flight-lib/itinerary';

const downloadsFolder = Cypress.config('downloadsFolder');
const xmldata = xmlEu.xmlDataFlight;
const cacheKey = xmldata.cacheKey;
const liquidCredentials = Cypress.env('liquid')?.LIQUID_ADMIN_PASSWORD;
const adminCreds = Cypress.env('newUser').NEW_USER_PASSWORD;
const liquidAdmin = stagingUsers.liquid.impersonation.email;
export class Invoice {
  static retrieveDownloadInvoiceFile() {
    let filename, filePath: { toString: () => string };
    cy.task<string>('getDataFromCache', 'bookingID').then((bookingId) => {
      cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
      cy.log('bookingId:' + bookingId);
      cy.task<string[]>('filesInDownload', downloadsFolder).then((fileNames) => {
        fileNames.forEach(function (file: any) {
          cy.log('File: ' + file);
          if (file.includes(bookingId)) {
            filename = file.toString();
            cy.log('FileName : ' + filename);
            filePath = downloadsFolder + `/${filename}`;
            cy.task('putDataInCache', {
              key: 'bookingInvoicePDFFileName',
              data: filePath
            }).then(() => {
              cy.log('FilePath' + filePath);
            });
          }
        });
      });
    });
  }

  static verifyIfFileIsDownloaded(fileNameFromUI: string) {
    return cy
      .task<string[]>('filesInDownload', downloadsFolder)
      .then((fileNames) => {
        for (let i = 0; i < fileNames.length; i++) {
          const file = fileNames[i];
          if (file.includes(fileNameFromUI)) {
            return true;
          }
        }
        return false;
      })
      .should((result) => {
        expect(result).to.be.true;
      });
  }

  static verifyHotelBookingInvoiceDetails() {
    HotelItinerary.verifyHotelItineraryPage();
    HotelItinerary.storeItineraryURl();
    FlightItinerary.forcePDFSyncAPI();
    Utility.loginAsAdmin(adminCreds);
    HotelItinerary.goToItineraryPage();
    HotelItinerary.storeHotelBookingInformation();
    Invoice.retrieveDownloadInvoiceFile();
    Invoice.retrieveAndConvertPDFInvoiceDetailsToHTML();
    HotelItinerary.validateHotelBookingDetailsInInvoice();
  }
  static verifyRailBookingInvoiceDetails() {
    TrainItinerary.goToItineraryPage();
    CommerceShared.visitViewInvoicePage();
    Invoice.retrieveDownloadInvoiceFile();
    Invoice.retrieveAndConvertPDFInvoiceDetailsToHTML();
    InvoiceValidation.checkBookingId();
  }

  static retrieveAndConvertPDFInvoiceDetailsToHTML() {
    cy.task('getDataFromCache', 'bookingInvoicePDFFileName').then((hotelFileName) => {
      cy.task('toHtml', hotelFileName).then((html) => {
        cy.document({ log: true }).invoke({ log: true }, 'write', html);
      });
    });
  }

  static deleteFileFromFolder() {
    let pdfFilename, filePath: { toString: () => string };
    cy.task<string>('getDataFromCache', 'bookingID').then((bookingId) => {
      cy.task<string[]>('filesInDownload', downloadsFolder).then((fileNames) => {
        fileNames.forEach(function (file: any) {
          if (file.includes(bookingId)) {
            pdfFilename = file.toString();
            filePath = downloadsFolder + `/${pdfFilename}`;
            cy.task('getDataFromCache', 'bookingInvoicePDFFileName').then(() => {
              cy.log('Delete FilePath' + filePath);
              cy.exec(`rm ${filePath}`); // assert that the file is deleted
            });
          }
        });
      });
    });
  }
  static requiredXmlContentValidations() {
    cy.allure().logStep('Get XML content from cache');
    Utility.getXmlContentFromCache(cacheKey).then((xmlContent: any) => {
      const xmlDoc = Utility.parseXmlContent(xmlContent);
      //VersNbr value is set to 201000001
      const versNbrElement = xmlDoc.getElementsByTagName('VersNbr')[0];
      const versNbrValue = versNbrElement.textContent;
      expect(xmldata.VersNbr).to.equal(versNbrValue);
      //submrIdValue is XMLTRIP142
      const submrIdElement = xmlDoc.getElementsByTagName('SubmrId')[0];
      const submrIdValue = submrIdElement.textContent;
      expect(xmldata.SubmrId).to.equal(submrIdValue);
      //MsgSeqNbrValue is 9 digit number
      const msgSeqNbrElement = xmlDoc.getElementsByTagName('MsgSeqNbr')[0];
      const msgSeqNbrValue = msgSeqNbrElement.textContent;
      if (msgSeqNbrValue !== null && msgSeqNbrValue !== undefined) {
        expect(msgSeqNbrValue.trim().length).to.equal(9);
      } else {
        cy.log('MsgSeqNbrValue is null or undefined');
      }
      //CreateDtValue is current date in format YYYYMMDD
      const createDtElement = xmlDoc.getElementsByTagName('CreateDt')[0];
      const createDtValue = createDtElement.textContent;
      if (createDtValue !== null && createDtValue !== undefined) {
        const regex = /^\d{8}$/; // YYYYMMDD format
        expect(createDtValue.trim()).to.match(regex);
      } else {
        cy.log('CreateDtValue is not in YYYYMMDD format');
      }
      //CreateTmValue is current time in format HHMMSS
      const createTmElement = xmlDoc.getElementsByTagName('CreateTm')[0];
      const createTmValue = createTmElement.textContent;
      if (createTmValue !== null && createTmValue !== undefined) {
        const regex = /^\d{6}$/; // HHMMSS format
        expect(createTmValue.trim()).to.match(regex);
      } else {
        cy.log('CreateTmValue is not in HHMMSS format');
      }
      //providerNmValue is Navan
      const providerNmElement = xmlDoc.getElementsByTagName('ProviderNm')[0];
      const providerNmValue = providerNmElement.textContent;
      expect(xmldata.ProviderName).to.equal(providerNmValue);
      //TransSeqNbrValue is 9 digit number
      const transSeqNbrElement = xmlDoc.getElementsByTagName('TransSeqNbr')[0];
      const transSeqNbrValue = transSeqNbrElement.textContent;
      if (transSeqNbrValue !== null && transSeqNbrValue !== undefined) {
        const regex = /^\d{9}$/;
        expect(transSeqNbrValue.trim().length).to.equal(9);
        expect(regex.test(transSeqNbrValue.trim())).to.be.true;
      } else {
        cy.log('TransSeqNbrValue is not in 9 digit number format');
      }
      //TransDtValue is current date in format YYYYMMDD
      const transDtElement = xmlDoc.getElementsByTagName('TransDt')[0];
      const transDtValue = transDtElement.textContent;
      if (transDtValue !== null && transDtValue !== undefined) {
        const regex = /^\d{8}$/; // YYYYMMDD format
        expect(transDtValue.trim()).to.match(regex);
      } else {
        cy.log('TransDtValue is not in YYYYMMDD format');
      }
      //TransDtValue is current date in format HHMMSS
      const transTmElement = xmlDoc.getElementsByTagName('TransTm')[0];
      const transTmValue = transTmElement.textContent;
      if (transTmValue !== null && transTmValue !== undefined) {
        const regex = /^\d{6}$/; // HHMMSS format
        expect(transTmValue.trim()).to.match(regex);
      } else {
        cy.log('TransTmValue is not in HHMMSS format');
      }
      //dbCrIndValue is D or C
      const dbCrIndElement = xmlDoc.getElementsByTagName('DbCrInd')[0];
      const dbCrIndValue = dbCrIndElement.textContent;
      expect(xmldata.dbCrIndValue).to.equal(dbCrIndValue);
      // destNmValue is alphanumeric
      const destNmElement = xmlDoc.getElementsByTagName('DestNm')[0];
      const destNmValue = destNmElement.textContent;
      if (destNmValue !== null && destNmValue !== undefined) {
        const alphanumericPattern = /^[a-zA-Z0-9\s]+$/;
        expect(destNmValue.trim()).to.match(alphanumericPattern);
      } else {
        cy.log('DestNmValue is not in alphanumeric format');
      }
      //dprtDtValue is current date in format YYYYMMDD
      const dprtDtElement = xmlDoc.getElementsByTagName('DprtDt')[0];
      const dprtDtValue = dprtDtElement.textContent;
      if (dprtDtValue !== null && dprtDtValue !== undefined) {
        const dateFormatPattern = /^\d{4}\d{2}\d{2}$/; // YYYYMMDD format
        expect(dprtDtValue.trim()).to.match(dateFormatPattern);
      } else {
        cy.log('DestNmValue is not in YYYYMMDD format');
      }
      //suplrNmValue is alphanumeric
      const suplrNmElement = xmlDoc.getElementsByTagName('SuplrNm')[0];
      const suplrNmValue = suplrNmElement.textContent;
      if (suplrNmValue !== null && suplrNmValue !== undefined) {
        const alphanumericPattern = /^[a-zA-Z0-9\s]+$/;
        expect(suplrNmValue.trim()).to.match(alphanumericPattern);
      } else {
        cy.log('DestNmValue is not in alphanumeric format');
      }
      //invIndValue is N or Y
      const invIndElement = xmlDoc.getElementsByTagName('InvInd')[0];
      const invIndValue = invIndElement.textContent;
      expect(xmldata.invInd).to.equal(invIndValue);
      //invDtValue is current date in format YYYYMMDD
      const invDtElement = xmlDoc.getElementsByTagName('InvDt')[0];
      const invDtValue = invDtElement.textContent;
      if (invDtValue !== null && invDtValue !== undefined) {
        const dateFormatPattern = /^\d{4}\d{2}\d{2}$/; // YYYYMMDD format
        expect(invDtValue.trim()).to.match(dateFormatPattern);
      } else {
        cy.log('DestNmValue is not in YYYYMMDD format');
      }
    });
  }
  static bulkDownloadCall() {
    cy.getLiquidStatementID(liquidAdmin, liquidCredentials); //getting the statement id
    cy.requestBulkDownloadAPI(liquidAdmin, liquidCredentials); //requesting the bulk download like clicking Download button
    cy.bulkDownloadAPI(liquidAdmin, liquidCredentials); //getting the bulk download response
    Invoice.bulkDownLoadValidations(); //validating the bulk download response
  }
  static bulkDownLoadValidations() {
    cy.task('getDataFromCache', 'bulkDownload').then((response: any) => {
      const url = response.url;
      cy.request({
        url: url,
        encoding: 'binary'
      }).then((response) => {
        expect(response.status, 'Zip File Download').to.equal(HttpStatusCodes.Ok);
        expect(response.headers['content-type']).to.equal('application/zip');
        expect(response.headers['content-disposition']).to.equal('attachment');
        expect(response.headers['server']).to.equal('AmazonS3');
      });
    });
  }
  static forceSyncAPI() {
    cy.task('getDataFromCache', 'bookingUuid').then((bookingUuid) => {
      cy.forceSyncAPI(bookingUuid);
      cy.allure().logStep('Force Sync API Call bookingUuid-> ' + bookingUuid);
    });
  }
  static invoiceTotalAmountValidation() {
    cy.allure().logStep('Invoice Total Amount Validation from Ledger and Invoice');
    cy.task('getDataFromCache', 'ledgerData').then((ledgerData: any) => {
      const totalAmount = ledgerData.total_amount.amount;
      const formattedAmount = totalAmount.toFixed(2);
      cy.allure().logStep('total amount in Ledger:' + formattedAmount);
      cy.log('total amount in Ledger:' + formattedAmount);
      cy.allure().logStep('Total amount validation in invoice');
      cy.contains(formattedAmount);
    });
  }
  static invoiceBaseAmountValidation() {
    cy.allure().logStep('Invoice Base and Tax Amount Validation from Ledger in Invoice');
    cy.task('getDataFromCache', 'ledgerData').then((ledgerData: any) => {
      const baseAmount = ledgerData.base_amount.amount;
      const taxAmount = ledgerData.tax_amount.amount;
      const baseFormattedAmount = baseAmount.toFixed(2);
      const taxFormattedAmount = taxAmount.toFixed(2);
      cy.allure().logStep('total amount in Ledger:' + baseFormattedAmount);
      cy.log('total amount in Ledger:' + baseFormattedAmount);
      cy.contains(baseFormattedAmount);
      cy.contains(taxFormattedAmount);
    });
  }
  static retrieveDownloadInvoiceFileWithBookingID(bookingId: string) {
    let filename, filePath: { toString: () => string };
    cy.log('bookingId:' + bookingId);
    cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);
    cy.task<string[]>('filesInDownload', downloadsFolder).then((fileNames) => {
      fileNames.forEach(function (file: any) {
        if (file.includes(bookingId)) {
          filename = file.toString();
          cy.log('FileName : ' + filename);
          filePath = downloadsFolder + `/${filename}`;
          cy.task('putDataInCache', {
            key: 'bookingInvoicePDFFileName',
            data: filePath
          }).then(() => {
            cy.log('FilePath' + filePath);
          });
        }
      });
    });
  }
  static deleteFileFromFolderByBookingId(bookingId: string) {
    let pdfFilename, filePath: { toString: () => string };
    cy.task<string[]>('filesInDownload', downloadsFolder).then((fileNames) => {
      fileNames.forEach(function (file: any) {
        if (file.includes(bookingId)) {
          pdfFilename = file.toString();
          filePath = downloadsFolder + `/${pdfFilename}`;
          cy.task('getDataFromCache', 'bookingInvoicePDFFileName').then(() => {
            cy.exec(`rm ${filePath}`); // assert that the file is deleted
          });
        }
      });
    });
  }
}
