import { MessageService } from "primeng/api";
import { API } from "../services/api.service";
import { Injectable } from "@angular/core";
import { Title } from "@angular/platform-browser";
import { ValidationService } from "./validation.service";
import * as moment from "moment";
import { FileUpload } from "primeng/fileupload";
import jsPDF from "jspdf";
import * as FileSaver from "file-saver";
import autoTable from 'jspdf-autotable';
import { UserLoginData } from "../models/common-model/userModel";
import { securityFunctions } from "./security";
import { UserLog } from "../models/common-model/user-logout.model";
import { Subscription, interval } from "rxjs";
import { environment } from "src/environments/environment";
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';

@Injectable({
    providedIn: 'root'
})
export class CommonFunctionService {
    LoginUserData: UserLoginData
    constructor(
        public MsgService: MessageService,
        public ApiServ: API,
        public validationService: ValidationService,
        public titleService: Title,
        public router:Router
    ) {
        this.LoginUserData = securityFunctions.getSessionStorage('LoginUserData') ? JSON.parse(securityFunctions.getSessionStorage('LoginUserData')) : null
        this.clientId = environment.client_id
    }
    clientId = ''
    logo;
    AllMenu;
    ChangeStatusAllowed = false;
    DownloadFilesAllowed = false;
    environmentObj = environment;
    ddLoader = {
        country: false,
        city: false,
        Currency: false,
        vendor: false,
    };
    MenuTabList = {
        Overview: { val:false, link:'Services/Hotel/HotelManage/OverView', IsActive: false, Download: false},
        MealAddOn: { val:false, link:'Services/Hotel/HotelManage/HotelMealAdd', IsActive: false, Download: false},
        Rooms: { val:false, link:'Services/Hotel/HotelManage/HotelAddRoom', IsActive: false, Download: false},
        HotelSeason: { val:false, link:'Services/Hotel/HotelManage/AddSeason', IsActive: false, Download: false},
        RoomContract: { val:false, link:'Services/Hotel/HotelManage/RoomContractAdd', IsActive: false, Download: false},
        MinStay: { val:false, link:'Services/Hotel/HotelManage/AddMinStay', IsActive: false, Download: false},
        RoomAllocation: { val:false, link:'Services/Hotel/HotelManage/AddAllocation', IsActive: false, Download: false},
        HotelBlockDates: { val:false, link:'Services/Hotel/HotelManage/HotelAddBlockDate', IsActive: false, Download: false},
        HotelOffers: { val:false, link:'Services/Hotel/HotelManage/AddOffer', IsActive: false, Download: false},
        HotelSupplements: { val:false, link:'Services/Hotel/HotelManage/AddSuppliment', IsActive: false, Download: false},
    }
    CurrencyList = [];
    CountryList = [];
    CityList = [];
    agencyData = [];
    timer;
    AllVendor = []
    //  =============================== normal function ==========================

    /**
     * this function for show message
     * @param check boolean
     * @param message text
     */
    public showMessage(check, message, type?) {
        this.MsgService.add({
            severity: type ? type : check ? "success" : "error",
            detail: message,
        });
    };

    /**
       * @author Ayaan kazi
       * last updated by Abdul Razzak on 03-06-2024
       * @param otpInp 
       * @param otpBox 
       */
    focusEmptyOtpInp(otpInp, otpBox) {
        let targetOtpInput = otpInp.target;
        const otpInputWrapper = targetOtpInput.closest('.ng-otp-input-wrapper');
        const inputList = [...otpInputWrapper.querySelectorAll('input')];
        let ind = inputList.findIndex(z => z.getAttribute('id') == targetOtpInput.id);
        if (ind == -1 || inputList[ind].value == '') {
            for (let i = 0; i <= inputList.length; i++) {
                let inp = inputList[i];
                if (inp?.value == '') {
                    let id = inp.getAttribute('id');
                    otpBox.focusTo(id);
                    break;
                }
            }
        }
    };

    // check Token expire time 
    /**
     * @param check pass boolean for check time expire or not
     */
    CheckTokenExpireTime(check) {
        const currentISOString = moment.utc(this.ApiServ.getAdjustedLocalTime()).format('YYYY-MM-DD HH:mm:ss');
        const time1 = moment.utc(sessionStorage.getItem('JwtTokenExpiry')).subtract(3, 'seconds').format('YYYY-MM-DD HH:mm:ss');
        const isTime1AfterTime2 = this.isTime1AfterTime2(time1, currentISOString);
        if (isTime1AfterTime2) {
            let postdata = {
                "JwtToken": sessionStorage.getItem('JwtToken'),
                "RefreshToken": sessionStorage.getItem('RefreshToken')
            }
            this.ApiServ.AdminPost('/JWT/RefreshToken', postdata).subscribe(res => {
                if (!res.Status) {
                    this.loginOut();
                } else {
                    sessionStorage.setItem('JwtToken', res.JwtToken);
                    sessionStorage.setItem('RefreshToken', res.RefreshToken);
                    sessionStorage.setItem('JwtTokenExpiry', res.JwtTokenExpiry);
                    check ? window.location.href = "/Home/Dashboard" : '';
                }
            })
        } else {
            check ? window.location.href = "/Home/Dashboard" : '';
        }
    };
    isTime1AfterTime2(time1, time2) {
        const date1 = new Date(time1); // Create a Date object for time1
        const date2 = new Date(time2); // Create a Date object for time2
        return date1 < date2 ? true : false; // Compare the two Date objects
    };
    //  ----------------------------------------------  Export file ---------------------------------------------- 
    /**
     * this function for download excel
     * @param GetallData all data
     * @param title_list header and property list
     * @param file_name file name
     */
    public exportExcel(GetallData, title_list, file_name) {
        let bookResultResp = GetallData.map(el => {
            let obj = {}
            title_list.forEach(title => obj[title.header] = el[title.field])
            return obj;
        });
        import("xlsx").then((xlsx) => {
            console.log(xlsx);
            const worksheet = xlsx.utils.json_to_sheet(bookResultResp);
            const workbook = { Sheets: { data: worksheet }, SheetNames: ["data"] };
            const excelBuffer: any = xlsx.write(workbook, {
                bookType: "xlsx",
                type: "array",
            });
            this.saveAsExcelFile(excelBuffer, file_name);
        });
    }
    /**
     * @param buffer 
     * @param fileName 
     */
    saveAsExcelFile(buffer: any, fileName: string): void {
        import("file-saver").then((abc) => {
            let EXCEL_TYPE =
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8";
            let EXCEL_EXTENSION = ".xlsx";
            const data: Blob = new Blob([buffer], {
                type: EXCEL_TYPE,
            });
            console.log(FileSaver);
            FileSaver.saveAs(
                data,
                fileName + "_export_" + new Date().getTime() + EXCEL_EXTENSION
            );
        });
    }
    /**
     * this function for download PDF
     * @param GetallData all data
     * @param title_list header and property list
     * @param file_name file name
     */
    public exportPdf(GetallData, title_list, file_name) {
        let bookResultResp = GetallData.map(el => {
            let data_Array = [];
            title_list.forEach(title => data_Array.push(el[title.field]))
            return data_Array
        });
        let key_Array = [];
        title_list.forEach(title => key_Array.push(title.header))
        const head = [key_Array]
        const doc = new jsPDF("l", "ex", [100, 280]);
        autoTable(doc, {
            head: head,
            body: bookResultResp,
            didDrawCell: (bookResultResp) => { },
        });
        doc.save(file_name);
    }
    //   ----------------------------------------------  amount Formater ---------------------------------------------- 
    /**
     * 
     * @param amount 
     * @param amountFormat 
     * @param amountFormatDecimalSpliter 
     * @returns 
     */
    public amountFormater(amount, amountFormat, amountFormatDecimalSpliter) {
        amountFormat = amountFormat != null && amountFormat != '' ? amountFormat : '#,###,###,###.##';
        amountFormatDecimalSpliter = amountFormatDecimalSpliter != null && amountFormatDecimalSpliter != '' ? amountFormatDecimalSpliter : '.';
        let outputAmount = amount;
        let splitAmount = amount.toString().split('.');
        let splitAmountFormat = amountFormat
            .toString()
            .split(amountFormatDecimalSpliter);
        let amountSplitList =
            splitAmount != null && splitAmount.length > 0
                ? splitAmount[0].split('').reverse()
                : [];
        let decimalAmountSplitList =
            splitAmount != null && splitAmount.length > 1
                ? splitAmount[1].split('')
                : [];
        let amountFormatSplitList =
            splitAmountFormat != null && splitAmountFormat.length > 0
                ? splitAmountFormat[0].split('').reverse()
                : [];
        let decimalAmountFormatSplitList =
            splitAmountFormat != null && splitAmountFormat.length > 1
                ? splitAmountFormat[1].split('')
                : [];

        decimalAmountFormatSplitList.forEach((x, index) => {
            decimalAmountFormatSplitList[index] = decimalAmountSplitList[index]
                ? decimalAmountSplitList[index]
                : '0';
        });
        let amountSplitListTemp = [];
        let amountIndex = 0;
        amountFormatSplitList.forEach((x, index) => {
            if (amountFormatSplitList[index] == '#' && amountSplitList[amountIndex]) {
                amountSplitListTemp.push(amountSplitList[amountIndex]);
                amountIndex += 1;
            } else if (amountSplitList[amountIndex]) {
                amountSplitListTemp.push(amountFormatSplitList[index]);
            }
        });

        if (decimalAmountFormatSplitList && decimalAmountFormatSplitList.length > 0) {
            outputAmount =
                amountSplitListTemp.reverse().join('') +
                amountFormatDecimalSpliter +
                decimalAmountFormatSplitList.join('');
        } else {
            outputAmount =
                amountSplitListTemp.reverse().join('')
        }
        return outputAmount;
    }
    // ---------------------------------------------- passsword update functions  ---------------------------------------------------------

    // This function for password criteria
    password_criteria(password_Value) {
        password_Value.length >= 8 ? this.password_criteria_obj.is_length = true : this.password_criteria_obj.is_length = false;
        password_Value.match(this.validationService.regExps.lower_case) ? this.password_criteria_obj.is_lowerCase = true : this.password_criteria_obj.is_lowerCase = false;
        password_Value.match(this.validationService.regExps.Capital_case) ? this.password_criteria_obj.is_Uppercase = true : this.password_criteria_obj.is_Uppercase = false;
        password_Value.match(this.validationService.regExps.numbers) ? this.password_criteria_obj.is_numbers = true : this.password_criteria_obj.is_numbers = false;
        password_Value.match(this.validationService.regExps.special_characters) ? this.password_criteria_obj.is_special_characters = true : this.password_criteria_obj.is_special_characters = false;
    };
    password_criteria_obj = {
        is_lowerCase: false,
        is_Uppercase: false,
        is_Capital_case: false,
        is_numbers: false,
        is_special_characters: false,
        is_length: false
    };

    public isFormControlHasError(e, validationType) {
        let result = e.hasError(validationType) && (e.dirty || e.touched);
        return result;
    };

    // for create priority update array of object
    // createPriorityObj(data, rule) {
    //     return data.map(e => ({ priority: e.priority, [rule]: e[rule] }));
    // };
    // /**
    //  * Updates the priority and sets the 'is_change' flag for an element in the given list
    //  * based on a specified rule identifier property.
    //  * 
    //  * @param listToUpdate - The array of objects 
    //  * @param targetRuleId - The value of the rule identifier to find the target element.
    //  * @param newPriority - The new priority value to set.
    //  * @param ruleIdProperty - The property name representing the rule identifier in each object.
    //  */
    // updatePriorityByRuleId(listToUpdate, targetRuleId, newPriority, ruleIdProperty) {
    //     if (newPriority !== "") {
    //         const targetElement = listToUpdate.find(item => item[ruleIdProperty] === targetRuleId);
    //         if (targetElement) {
    //             targetElement.is_change = true;
    //             targetElement.priority = parseInt(newPriority);
    //         };
    //     };
    // };

    // -------------------------------------------------------------Date Formmat function -------------------------------------------------- 
    /**
     * Converts a UTC date to a formatted local time string.
     * @author Abdul Razzak
     * @param date 
     * @param format 
    */
    UtcToLocaleTime(date, format = 'DD MMM YYYY, HH:mm:ss') {
        let localeTime = moment.utc(date).local();
        let formattedTime = localeTime.format(format);
        return formattedTime;
    }
    GetTimeZoneGMT() {
        let _date = new Date().getTimezoneOffset();
        return `${((_date / 60) > 0 ? "-" : "+")}${Math.floor(Math.abs(_date / 60))} hours ${Math.abs(_date % 60)} minutes`
    };

    convertDateToSave(date: Date) {
        return moment(date).format('YYYY-MM-DD') + 'T00:00:00Z'
    };
    convertDateToSaveWithoutTime(date: Date) {
        return moment(date).format('YYYY-MM-DD')
    };
    convertDateWithTimeToShow(date: Date) {
        return moment(date).format('DD MMM YYYY, HH:mm:ss')
    };
    convertDateToShow(date: Date) {
        return moment(date).format('DD MMM YYYY')
    };

    // ----------------------------------------------------------- image update function ------------------------------------------------------------
    /**
     * for check image file 
     * @param file 
     * @param controls 
     * @param filedata
     * @author Abdul Razzak 
     */
    checkImageFile(file, controls, filedata: FileUpload) {
        const reader = new FileReader();
        reader.readAsText(file); // Read as binary data
        reader.onload = (e) => {
            const binaryString = e.target.result as string;
            const hasScriptTag = this.hasScriptTagInBinary(binaryString);
            if (hasScriptTag) {
                filedata.clear();
                this.showMessage(false, 'Invalid file (contains script tag)');
            } else {
                controls.setValue(file);
            }
        };
    };

    /**
     * Image script validation 
     * @author Abdul Razzak
     */
    hasScriptTagInBinary(binaryData: string) {
        // This is a simplified and potentially unreliable approach
        const scriptTagRegex = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/g;
        return scriptTagRegex.test(binaryData);
    };

    // ------------------------------------------------------------ api calls function---------------------------------------------------------
    GetCurrencyList(val) {
        if (val.length >= 2 || val == 'ALL') {
            this.ddLoader.Currency = true;
            clearTimeout(this.timer);
            this.timer = setTimeout(() => {
                let request = {
                    "langcode": "en",
                    "query": val == 'ALL' ? '' : val
                }
                this.ApiServ.AdminGoPost(`/MasterSearch/GetAllCurrency`, request).subscribe(res => {
                    if (res) {
                        this.CurrencyList = res?.Result;
                        this.ddLoader.Currency = false;
                    }
                });
            }, 500);
        };
        if (!val) {
            this.CurrencyList = [];
        }
    };

    /**
     * this function  for get standalone feature by code
     * @param pageId  page id
     */
    getFeatures(pageId) {
        return this.ApiServ.Get("/MenuMasterNew/GetAllFeatureCode/2110180851430030870/" + pageId)
    }

    getCountryBySearch(val) {
        if (val.length >= 2) {
            this.ddLoader.country = true;
            clearTimeout(this.timer);
            this.timer = setTimeout(() => {
                this.ApiServ.AdminGet(`/MasterSearch/GetAllCountry/en/` + val).subscribe(res => {
                    if (res) {
                        this.CountryList = res;
                        this.ddLoader.country = false;
                    }
                });
            }, 500);
        }
        if (!val) {
            this.CountryList = [];
        }
    };
    // This function is used for country search by name.

    checkCountryExist = false;
    getCitySearchByCountryCode(val, country_code) {
        if (country_code) {
            this.checkCountryExist = false;
            if (val.length >= 2) {
                this.ddLoader.city = true;
                clearTimeout(this.timer);
                this.timer = setTimeout(() => {
                    this.ApiServ.AdminGet(`/MasterSearch/GetCitySearch/en/${country_code}/` + val).subscribe(res => {
                        if (res) {
                            this.CityList = res;
                            this.ddLoader.city = false;
                        }
                    });
                }, 500);
            }
            if (!val) {
                this.CityList = [];
            }
        } else this.checkCountryExist = true;
    };
    ExtranetVendorMaster(val, check) {
        if (val.length >= 2) {
            this.ddLoader.vendor = true;
            clearTimeout(this.timer);
            this.timer = setTimeout(() => {
                this.FetchExtranetVendorMaster(val, check)
            }, 500);
        }
        if (!val) {
            this.AllVendor = [];
        }
    };

    FetchExtranetVendorMaster(val, check) {
        let searchObj = {
            vendor_name: check ? val : '',
            extranet_vendor_id: !check ? val : '',
        };
        return this.ApiServ.AdminGoPost('/ExtranetVendorMaster/GetAll', searchObj)
    };
    loginOut() {
        let loginData = sessionStorage.getItem('IP');
        this.LoginUserData = JSON.parse(securityFunctions.getSessionStorage('LoginUserData'));
        try {
            let userLogModel = new UserLog();
            userLogModel.ip = loginData['iP'];
            userLogModel.ip_city = loginData['city'];
            userLogModel.ip_country_code = loginData['countryCode'];
            userLogModel.ip_lat = loginData['lat'];
            userLogModel.ip_lon = loginData['lon'];
            userLogModel.ip_proxy = loginData['proxy'];
            userLogModel.user_id = this.LoginUserData.user_id;
            userLogModel.user_type = this.LoginUserData.user_type;
            this.ApiServ.AdminPost("/Log/SaveLogoutLog", userLogModel).subscribe(d => {
                securityFunctions.resetSessionStoage('lastLogin')
                securityFunctions.resetSessionStoage('LoginUserData')
                securityFunctions.resetSessionStoage('IP')
                securityFunctions.resetSessionStoage('userName')
                securityFunctions.resetSessionStoage('JwtToken')
                securityFunctions.resetSessionStoage('RefreshToken')
                securityFunctions.resetSessionStoage('JwtTokenExpiry')
                sessionStorage.removeItem('selMenu');
                window.location.href = '/Auth/Login';
            });
        } catch (error) {
            window.location.href = '/Auth/Login';
        }
    };

    // 
    displayPosition = false;
    position: string;
    public subscription: Subscription;
    remainingTime: number;
    StartTimer() {
        const source = interval(1000);
        // Subscribe to the interval observable
        this.subscription = source.subscribe(() => {
            // Get the current time in milliseconds
            const currentTime = moment.utc(this.ApiServ.getAdjustedLocalTime()).valueOf();
            const LastEndpointCallTime = moment.utc(sessionStorage.getItem('LastEndpointCallTime')).valueOf();
            // Get the token expiry time from sessionStorage
            const tokenExpiry = moment.utc(sessionStorage.getItem('JwtTokenExpiry'));
            // Calculate the time difference between token expiry and current time in milliseconds
            const timeDifference = tokenExpiry.valueOf() - currentTime;
            // Calculate the diffence between current time and the last endpoint call time.
            const diff_between_endpoint_call = currentTime - LastEndpointCallTime
            
            // Check if time difference is less than or equal to 2 minutes (120000 milliseconds)
            if (timeDifference <= 120000) {
                if (this.displayPosition && this.remainingTime <= 0) {
                    this.exit();
                  } else {
                    if (diff_between_endpoint_call >= 780000) {
                // If excd is not set and displayPosition is not already true, set displayPosition to true
                if (!sessionStorage.getItem('excd') && !this.displayPosition) {
                    this.displayPosition = true;
                }

                // Calculate remaining time in seconds
                const remainingTimeSeconds = tokenExpiry.diff(moment.utc(this.ApiServ.getAdjustedLocalTime()), 'seconds');
                // Update remainingTime property
                this.remainingTime = remainingTimeSeconds;
                // If remaining time is less than or equal to 0, call exit function
                if (this.remainingTime <= 0) {
                    this.exit();
                }
            } else {
                this.extendJWTTime();
              }
            }
            }
        });
    };
    exit() {
        this.displayPosition = false;
        sessionStorage.removeItem('excd');
        this.loginOut();
    };
    extendJWTTime() {
        this.stopTimer();
        let postdata = {
          "JwtToken": sessionStorage.getItem('JwtToken'),
          "RefreshToken": sessionStorage.getItem('RefreshToken')
        };
        this.ApiServ.AdminPost('/JWT/RefreshToken', postdata).subscribe(res => {
          if (!res.Status) {
            this.loginOut();
          } else {
            sessionStorage.setItem('JwtToken', res.JwtToken);
            sessionStorage.setItem('RefreshToken', res.RefreshToken);
            sessionStorage.setItem('JwtTokenExpiry', res.JwtTokenExpiry);
            sessionStorage.setItem('RefreshTokenExpireAt', res.RefreshTokenExpireAt);
            this.Close(true); 
            this.StartTimer();
          }
        })
      };
      stopTimer() {
        if (this.subscription) {
          this.subscription.unsubscribe();
          this.subscription = undefined;
        }
      };
      Close(check) {
        this.displayPosition = false;
        sessionStorage.setItem('excd', 'OK')
        if (check) {
          setTimeout(function () {
            sessionStorage.removeItem('excd');
          }, 10000); // 10000 milliseconds = 10 second
        }
      }
      AffiliateDetails(value, target, check, agencytype?, is_active?, is_cug?) {
        let obj = {
            AgencyId: check ? value : null,
            AgencyName: !check ? value : ''
        }
        if (value.length >= 3) {
            this.ddLoader[target] = true;
            clearTimeout(this.timer);
            this.timer = setTimeout(() => {
                this.ApiServ.PostGo(`/AgencyDetail/GetAllAffiliateDetail`, obj).subscribe(res => {
                    if (res) {
                        this.agencyData = res.result;
                        if (agencytype) {
                            if (agencytype == '211526104324609556' || agencytype == '211526104324609557') {
                                if (agencytype == '211526104324609556') this.agencyData = this.agencyData.filter(z => z.AgencyType == 'B2C');
                                if (agencytype == '211526104324609557') this.agencyData = this.agencyData.filter(z => z.AgencyType == 'B2B');
                            }
                            else this.agencyData = this.agencyData.filter(z => z.AgencyType == agencytype);
                        };
                        if(is_active) this.agencyData = res.result.filter(z => z.AgencyType == 'B2B' && z.IsActive);
                        if(is_cug) this.agencyData = res.result.filter(z => (z.AgencyType === "B2B" || z.is_cug) && z.IsActive);
                        if(!is_active && is_cug) this.agencyData = res.result.filter(z => (z.AgencyType === "B2B" || z.is_cug));
                        this.ddLoader[target] = false;
                    }
                });
            }, 500);
        } else {
            this.agencyData = [];
        }
    }
    public amountDefiner(amount, definer) {
        let outputAmount = amount;
        let splitAmount = amount.toString().split(".");
        if (splitAmount.length > 1 && splitAmount[1].length > 0) {
            let decimals = splitAmount[1].substr(0, definer);
            outputAmount = parseFloat(decimals.length > 0 ? `${splitAmount[0]}.${decimals}` : amount).toFixed(definer);
        } else {
            outputAmount = parseFloat(`${splitAmount[0]}.0}`).toFixed(definer)
        }
        return outputAmount;
    }

    getHeaderSize(logoElem) {
        const logo = logoElem.nativeElement;
        let header_height = 0;
        if (logo) {
            header_height = logo.clientHeight;
        }
        return header_height;
    }

    CheckActiveTabMenus(menulist){
        this.AllMenu = menulist;
        Object.keys(this.MenuTabList).forEach(e=>{
            const Menu = menulist.find(d=>d.page_data.includes(this.MenuTabList[e].link));
             if(Menu){
                this.MenuTabList[e].val = true;
                this.MenuTabList[e].Download = Menu.permission.Download;
                this.MenuTabList[e].IsActive = Menu.permission.Status;
             }
        });
        this.onRouteChange();
        this.router.events
        .pipe(filter(event => event instanceof NavigationEnd))  // Filter to get NavigationEnd event
        .subscribe(() => {
          this.onRouteChange();  // Trigger your function
        });

    }
    onRouteChange(): void {
        const currentUrl = this.router.url;
        const currentUrlMenu = this.AllMenu.find(d=>{
            if(d.page_data){
                const page_data = JSON.parse(d.page_data);
                return page_data.some(e=>currentUrl.includes(e.page_url.replaceAll('/$','')))
            }else {
                return false;
            }
        });
        if(currentUrlMenu){
            this.DownloadFilesAllowed = currentUrlMenu.permission.Download;
            this.ChangeStatusAllowed = currentUrlMenu.permission.Status;
        }
    }
}