import { HttpService } from "@nestjs/axios";
import { Injectable, Logger } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import mongoose from "mongoose";
import { JwtService } from '@nestjs/jwt';
import { CurrencyValuation } from "src/models/CurrencyValuation.schema";
import { CurrencyList } from "src/constant/CountryCodeToCurrency";
import { lastValueFrom, map, catchError, timeout, of, throwError, delay, take, retryWhen } from "rxjs";
import { AnalyticsReport, recordTypeEnum } from "src/models/AnalyticsReport.schema";
import * as moment from "moment";
import * as fs from 'fs';
import * as zlib from 'zlib'
import { parse } from 'csv-parse'
import { AppleAccount } from "src/models/AppleAccount.schema";
import { EventEmitter2 } from "@nestjs/event-emitter";
import { AnalyticsReportService } from "./AnalyticsReport.service";
import { CurrentStage } from "../enum/CurrentStage.enum";
import { Cron, CronExpression } from '@nestjs/schedule';
import * as path from 'path';
import { LoggerService } from "src/utils/logger.service";
import { jwtDecode } from 'jwt-decode';



@Injectable()
export class CronSyncService {

    CONST_REPORT_TYPES = {
        SALES: 'SALES',
        DOWNLOAD: 'DOWNLOAD'
    }
    APPLEDATEFORMAT = "YYYY-MM-DD"
    DATEFORMAT = "DD-MM-YYYY"

    constructor(
        @InjectModel("CurrencyValuation") private CurrencyValuationRepo: mongoose.Model<CurrencyValuation>,
        @InjectModel("AnalyticsReport") private analyticsReportRepo: mongoose.Model<AnalyticsReport>,
        @InjectModel("AppleAccount") private AppleAccountRepo: mongoose.Model<AppleAccount>,
        private analyticsService: AnalyticsReportService,
        private eventEmitter: EventEmitter2,
        private readonly httpService: HttpService,
        private jwtService: JwtService,
        private readonly LoggerService: LoggerService
    ) { }
    private readonly logger = new Logger(CronSyncService.name);


    // this crone is  perfectly running for staging server....
    // @Cron('0 18 * * *', { timeZone: 'Asia/Kolkata' })
    // async handleDailyAppleReportsSync() {
    //     try {
    //         console.log('crone Working everyday 7PM.........');
    //         const vendors = await this.AppleAccountRepo.find({});
    //         const fromDate = moment().subtract(1, 'days').format('YYYY-MM-DD');
    //         const reportTypes = [recordTypeEnum.SALES, recordTypeEnum.DOWNLOAD];
    //         this.LoggerService.logApiCall(`🔁 Starting Apple Report Sync for ${fromDate}`);

    //         for (const vendor of vendors) {
    //             for (const reportType of reportTypes) {
    //                 const alreadySynced = await this.analyticsReportRepo.findOne({
    //                     AccountID: vendor._id,
    //                     EventDate: new Date(fromDate),
    //                     type: reportType
    //                 });

    //                 if (!alreadySynced) {
    //                     try {
    //                         const syncResult = await this.doSyncAnalyticsReport(reportType, fromDate, vendor);
    //                         const successMsg = `✅ Synced ${reportType} for Vendor ${vendor.VendorID}: ${syncResult?.count || 0}`;
    //                         this.LoggerService.logApiCall(successMsg);
    //                     } catch (err) {
    //                         const errorMsg = `❌ Sync failed for ${vendor.VendorID} [${reportType}]`;
    //                         this.LoggerService.logApiCall(errorMsg);
    //                         console.error(errorMsg, err);
    //                     }
    //                 } else {
    //                     const alreadySyncedMsg = `⚠️ Already synced: ${vendor.VendorID} [${reportType}] on ${fromDate}`;
    //                     this.LoggerService.logApiCall(alreadySyncedMsg);
    //                 };
    //             };
    //         };
    //         this.LoggerService.logApiCall(`✅ Apple Report Sync Completed for ${fromDate}`);
    //     } catch (error) {
    //         this.LoggerService.logApiCall(`❌ Error in Apple Report Sync: ${error?.message}`);
    //         console.error(error, 'error......');
    //     };
    // };

    @Cron('0 30,50 17 * * *', { timeZone: 'Asia/Kolkata' })
    async handleDailyAppleReportsSync() {
        try {
            console.log('Cron working everyday 6PM.........');

            const vendors = await this.AppleAccountRepo.find({});
            const reportTypes = [recordTypeEnum.SALES, recordTypeEnum.DOWNLOAD];
            const daysToCheck = [1, 2, 3];

            this.LoggerService.logApiCall(`🔁 Starting Apple Report Sync (last ${daysToCheck.length} days)`);

            const tasks: Promise<void>[] = [];

            for (const vendor of vendors) {
                for (const reportType of reportTypes) {
                    for (const d of daysToCheck) {
                        const fromDate = moment().subtract(d, 'days').format('YYYY-MM-DD');

                        // Wrap each iteration in a self-executing async function
                        tasks.push(
                            (async () => {
                                const alreadySynced = await this.analyticsReportRepo.findOne({
                                    AccountID: vendor._id,
                                    EventDate: fromDate,
                                    type: reportType,
                                });

                                if (!alreadySynced) {
                                    try {
                                        const syncResult = await this.doSyncAnalyticsReport(reportType, fromDate, vendor);
                                        const successMsg = `✅ Synced ${reportType} for Vendor ${vendor.VendorID} on ${fromDate}: ${syncResult?.count || 0}`;
                                        this.LoggerService.logApiCall(successMsg);
                                    } catch (err) {
                                        const errorMsg = `❌ Sync failed for ${vendor.VendorID} [${reportType}] on ${fromDate}`;
                                        this.LoggerService.logApiCall(errorMsg);
                                        console.error(errorMsg, err);
                                    }
                                } else {
                                    const alreadySyncedMsg = `⚠️ Already synced: ${vendor.VendorID} [${reportType}] on ${fromDate}`;
                                    this.LoggerService.logApiCall(alreadySyncedMsg);
                                }
                            })()
                        );
                    }
                }
            }

            // Run all tasks in parallel
            await Promise.all(tasks);

            this.LoggerService.logApiCall(`✅ Apple Report Sync Completed (last ${daysToCheck.length} days)`);
        } catch (error) {
            this.LoggerService.logApiCall(`❌ Error in Apple Report Sync: ${error?.message}`);
            console.error(error, 'error......');
        }
    }

    @Cron('0 0,30 18 * * *', { timeZone: 'Asia/Kolkata' })
    async handleSixPMReports() {
        console.log('cron run 18:00'); 
        await this.handleDailyAppleReportsSync();
    }

    // this cron  is  particulaer  date range  
    // @Cron(CronExpression.EVERY_MINUTE)
    // async handleDailyAppleReportsSync() {
    //     try {
    //         const vendors = await this.AppleAccountRepo.find({});
    //         const reportTypes = [recordTypeEnum.SALES, recordTypeEnum.DOWNLOAD];

    //         // 👉 Manually define the dates you want to sync
    //         const datesToSync = ['2025-07-24', '2025-07-25'];

    //         for (const vendor of vendors) {
    //             for (const reportType of reportTypes) {
    //                 for (const dateStr of datesToSync) {
    //                     const alreadySynced = await this.analyticsReportRepo.findOne({
    //                         AccountID: vendor._id,
    //                         EventDate: new Date(dateStr),
    //                         type: reportType
    //                     });

    //                     if (!alreadySynced) {
    //                         try {
    //                             const syncResult = await this.doSyncAnalyticsReport(reportType, dateStr, vendor);
    //                             console.log(`✅ Synced ${reportType} for Vendor ${vendor.VendorID} on ${dateStr}:`, syncResult?.count || 0);
    //                         } catch (err) {
    //                             console.error(`❌ Sync failed for ${vendor.VendorID} [${reportType}] on ${dateStr}`, err);
    //                         }
    //                     } else {
    //                         console.log(`⚠️ Already synced: ${vendor.VendorID} [${reportType}] on ${dateStr}`);
    //                     }
    //                 }
    //             }
    //         }
    //     } catch (error) {
    //         console.error('❌ Error in handleDailyAppleReportsSync:', error);
    //     }
    // }


    // @Cron(CronExpression.EVERY_MINUTE)
    // async handleDailyAppleReportsSync() {
    //     try {


    //     console.log('cron running ...............');

    //     const vendors = await this.AppleAccountRepo.find({});
    //     console.log(vendors,'vendors............');

    //     const reportTypes = [recordTypeEnum.SALES, recordTypeEnum.DOWNLOAD];
    //     console.log(recordTypeEnum,'tyieisjw');

    //     for (const vendor of vendors) {
    //         console.log('vendorlooppppp first');

    //         for (const reportType of reportTypes) {
    //             console.log('second loopssssss');

    //             // 1. Check last synced date
    //             const lastSynced = await this.analyticsReportRepo.findOne(
    //                 { AccountID: vendor._id, type: reportType },
    //                 { sort: { EventDate: -1 }, projection: { EventDate: 1 } }
    //             );
    //             console.log(lastSynced,'lasyynejvykok');


    //             const maxAppleAvailableDate = moment().subtract(2, 'days'); // Apple thi max etlu j male

    //             // 2. Start from lastSynced + 1, fallback to 7 days ago
    //             let startDate = lastSynced
    //                 ? moment(lastSynced.EventDate).add(1, 'day')
    //                 : moment().subtract(7, 'days');

    //             // 3. Don't go beyond max available date
    //             const endDate = maxAppleAvailableDate;

    //             while (startDate.isSameOrBefore(endDate)) {
    //                 const syncDate = startDate.format('YYYY-MM-DD');

    //                 const alreadyExists = await this.analyticsReportRepo.findOne({
    //                     AccountID: vendor._id,
    //                     EventDate: new Date(syncDate),
    //                     type: reportType,
    //                 });

    //                 if (!alreadyExists) {
    //                     try {
    //                         const syncResult = await this.doSyncAnalyticsReport(reportType, syncDate, vendor);
    //                         console.log(`✅ Synced ${reportType} for ${vendor.VendorID} on ${syncDate}:`, syncResult?.count || 0);
    //                     } catch (err) {
    //                         console.error(`❌ Sync failed for ${vendor.VendorID} [${reportType}] on ${syncDate}`, err);
    //                     }
    //                 } else {
    //                     console.log(`⚠️ Already exists ${reportType} for ${vendor.VendorID} on ${syncDate}`);
    //                 }
    //                 startDate = startDate.add(1, 'day');
    //             }
    //         }
    //     }
    //     } catch (error) {
    //         console.log(error,'error');
    //     }
    // }

    // this  cron  is specifc retrive  data using the vendor  id 
    // @Cron(CronExpression.EVERY_5_MINUTES)
    // async handleDailyAppleReportsSync() {
    //     try {
    //         const targetVendorID = '89623384'; // Replace with actual VendorID
    //         const vendor = await this.AppleAccountRepo.findOne({ VendorID: targetVendorID });
    //         console.log(vendor, 'vendormmmmmmmmmmmmm');


    //         if (!vendor) {
    //             console.error(`❌ Vendor with ID ${targetVendorID} not found`);
    //             return;
    //         }

    //         const reportTypes = [recordTypeEnum.SALES, recordTypeEnum.DOWNLOAD];

    //         // 👉 Define date range
    //         const fromDate = moment('2025-06-26');
    //         const toDate = moment('2025-07-26');

    //         for (let date = fromDate.clone(); date.isSameOrBefore(toDate); date.add(1, 'day')) {
    //             const dateStr = date.format('YYYY-MM-DD');

    //             for (const reportType of reportTypes) {
    //                 const alreadySynced = await this.analyticsReportRepo.findOne({
    //                     AccountID: vendor._id,
    //                     EventDate: new Date(dateStr),
    //                     type: reportType
    //                 });

    //                 if (!alreadySynced) {
    //                     try {
    //                         const syncResult = await this.doSyncAnalyticsReport(reportType, dateStr, vendor);
    //                         console.log(`✅ Synced ${reportType} for Vendor ${vendor.VendorID} on ${dateStr}:`, syncResult?.count || 0);
    //                     } catch (err) {
    //                         console.error(`❌ Sync failed for ${vendor.VendorID} [${reportType}] on ${dateStr}`, err);
    //                     }
    //                 } else {
    //                     console.log(`⚠️ Already synced: ${vendor.VendorID} [${reportType}] on ${dateStr}`);
    //                 }
    //             }
    //         }
    //     } catch (error) {
    //         console.error('❌ Error in handleDailyAppleReportsSync:', error);
    //     };
    // };


    @Cron('0 15,45 * * * *', { timeZone: 'Asia/Kolkata' })
    async doSyncCountryWisevaluation() {
        console.log('cron corrency...');
        // console.log(CurrencyList?.length)
        return await new Promise(async (resolve, reject) => {
            const requests = CurrencyList.map((item, index) => this.convertCurrencyValue(item, "usd"))
            // try {
            //     const result = await Promise.all(requests);
            //     result.map(({ status, value, from, to }) => {
            //         if (status == true && value) {
            //             if (status == true) {
            //                 this.CurrencyValuationRepo.create({
            //                     currencyBase: "USD",
            //                     rates: value,
            //                     currency: from,
            //                     syncDate: new Date(),
            //                     createdAt: new Date(),
            //                 })
            //             }
            //         }
            //     });
            //     resolve({ status: true })
            // }
            // catch (error) {
            //     console.log(error)
            //     resolve({ status: false, error: JSON.stringify(error) })
            // }

            try {
                const result = await Promise.all(requests);

                // result.forEach((res) => {
                //     if (!res) return;

                //     const { status, value, from } = res;

                //     if (status && value) {
                //         this.CurrencyValuationRepo.create({
                //             currencyBase: "USD",
                //             rates: value,
                //             currency: from,
                //             syncDate: new Date(),
                //             createdAt: new Date(),
                //         });
                //     }
                // });

                const existingCurrencies = await this.CurrencyValuationRepo.find();
                const existingMap = new Map(
                    existingCurrencies.map((c) => [c.currency, c])
                );

                const operations = result.map(async (res) => {
                    if (!res || !res.status || !res.value) return null;

                    const { value, from } = res;

                    const data = {
                        currencyBase: "USD",
                        rates: value,
                        currency: from,
                        syncDate: new Date()
                    };

                    if (existingMap.has(from)) {
                        // 🔄 Update if already exists
                        return this.CurrencyValuationRepo.updateOne(
                            { currency: from },
                            { $set: data }
                        );
                    } else {
                        // 🆕 Insert if new
                        return this.CurrencyValuationRepo.create({
                            ...data,
                            createdAt: new Date(),
                        });
                    }
                });

                // Run all DB operations in parallel
                await Promise.all(operations.filter(Boolean));

                resolve({ status: true });
            } catch (error) {
                console.error("Error in syncing currency valuation:", error);
                resolve({ status: false, error: JSON.stringify(error) });
            };
        });
    };

    async doSyncReportInBatch(from, to, type, applevendor) {
        console.log("called")
        const dates = await this.enumerateDaysBetweenDates(from, to)

        const totalDates = dates?.length
        const recordsBetweenDates = await this.analyticsReportRepo.aggregate([
            {
                $match: {
                    EventDate: {
                        $gte: new Date(from),
                        $lte: new Date(to)
                    },
                    type: type.toUpperCase(),
                    AccountID: applevendor._id
                },
            },
            {
                $group: {
                    _id: { $dateToString: { format: "%Y-%m-%d", date: "$EventDate" } }
                }
            },
            {
                $project: {
                    _id: 0,
                    date: "$_id"
                }
            },
            {
                $group: {
                    _id: null,
                    dates: { $push: "$date" }
                }
            }
        ]);
        let filteredDates = []
        if (recordsBetweenDates?.length) {
            const datedRecords = recordsBetweenDates?.length ? recordsBetweenDates[0].dates.sort() : dates
            dates.forEach((elemnt) => {
                if (!datedRecords?.includes(elemnt)) {
                    filteredDates.push(elemnt)
                }
            })
        } else {
            filteredDates = dates
        }
        const requests = filteredDates.map((item, index) => this.doSyncAnalyticsReport(type, item, applevendor))
        console.log("--------TOTAL REQUEST:", requests?.length)
        console.log("RESOLVD------")
        const result = await Promise.all(requests);

        console.log("SYNCED")
        let sum = 0
        result.map((i) => {
            if (i?.count) {
                sum += i?.count
            }
        })
        return { status: true, count: sum, result }
    }

    // @OnEvent('AutomaticSync.Report')
    async doHandleSyncReportInBatchAfterCredsSync(vendorID) {
        console.log("IN EVENT for Syncing Batch Vendor Id", vendorID)
        const fromDate = moment().subtract(60, 'd').format('YYYY-MM-DD');
        const toDate = moment().subtract(7, 'd').format('YYYY-MM-DD');
        let syncArr = []
        // syncArr.push(this.doSyncReportInBatch(fromDate,toDate,recordTypeEnum.SALES,vendorID))
        // syncArr.push(this.doSyncReportInBatch(fromDate,toDate,recordTypeEnum.DOWNLOAD,vendorID))

    }

    async doSyncAnalyticsReport(ReportTYPE, date, applevendor = null): Promise<{
        status: boolean,
        count?: number,
        error?: any,
        code?: number,
        data?: any[],
        message?: string;
    }> {
        if (ReportTYPE !== recordTypeEnum.SALES && ReportTYPE !== recordTypeEnum.DOWNLOAD) {
            return { status: false }
        }

        const hitDate = !!date == true ? moment(date).format('YYYY-MM-DD') : moment()

        if (moment(hitDate).format("DD-MM-YYYY") == moment().format("DD-MM-YYYY")) {
            moment(hitDate).add(-3, 'days')
        }
        const baseUrl = await this.doGetReportsUrl(ReportTYPE, hitDate, applevendor)
        console.log("CALLIED----", hitDate)

        return await new Promise((resolve, reject) => {
            this.doFetchReports(baseUrl, applevendor).then((response) => {
                if (response?.status) {
                    console.log("CALLING----", hitDate)
                    this.doHandleDataExtractionFromZIP(response.data, hitDate, ReportTYPE, applevendor).then(async (extractedData) => {
                        if (extractedData?.status == true) {
                            // resolve({ status: false, error: err })
                            console.log("SAVING----", hitDate, extractedData.data?.length)
                            this.analyticsReportRepo.insertMany(extractedData.data)
                            console.log("RESOLVING------")
                            resolve(extractedData)
                        } else {
                            console.warn("❗ Extraction failed for", hitDate);
                            resolve({ status: false, error: "Extraction Failed" });
                        }
                    });
                } else {
                    if (response?.code === 401) {
                        console.warn("🔐 Unauthorized: Token expired or invalid for", hitDate);
                        resolve({
                            status: false,
                            code: response.code,
                            message: response.message
                        });
                    } else if (response?.code === 404) {
                        console.log("📄 Report not ready for", hitDate);
                        resolve(response);  // safe fallback
                    }
                    // else {
                    //     console.error("🚫 Unknown failure for", hitDate);
                    //     resolve({
                    //         status: false,
                    //         code: response.code,
                    //         message: response.message || "Unknown error"
                    //     });
                    // }

                }
                // if (response?.status == false) {
                //     if (response.code == 401) {
                //         return {
                //             status: false,
                //             code: response.code,
                //             message: response.message
                //         }
                //     }
                //     if (response.code == 404) {
                //         resolve(response)
                //     }
                // }
            })
        })
    }

    async doSyncHealth() {
        return {
            status: true,
            code: 200,
            message: 'success'
        }
    }

    async doHandleAccountsSyncing(file) {
        let results = []
        let jsonRecords = []

        const result: any = await new Promise((resolve, reject) => {
            fs.createReadStream(file.path)
                .pipe(parse({ delimiter: ',' }))
                .on('data', (data) => results.push(data))
                .on('end', async () => {
                    const fromDate = moment().subtract(60, 'd').format('YYYY-MM-DD');
                    const toDate = moment().subtract(1, 'd').format('YYYY-MM-DD');
                    // const fromDate = moment('2025-09-01').format('YYYY-MM-DD');
                    // const toDate = moment('2025-09-05').format('YYYY-MM-DD');
                    let requestArr = []
                    let vendorsInStack = []
                    for (let i = 1; i < results.length; i++) {
                        const element = results[i];
                        let tempArr: any = {}
                        for (let jindex = 0; jindex < element.length; jindex++) {
                            const jElement = element[jindex];
                            tempArr[results[0][jindex].replace(/\s+/g, '')] = jElement
                        }
                        let record = await this.AppleAccountRepo.findOne({
                            VendorID: tempArr.VenderID
                        })
                        if (record) {
                            // await this.AppleAccountRepo.updateMany(
                            //     {},
                            //     { $set: { InitialSyncStatus: CurrentStage.INPROGRESS } }
                            // )
                            // await this.AppleAccountRepo.updateOne({ VendorID: record.VendorID }, { $set: { AccountName: tempArr.AccountName } })
                            await this.AppleAccountRepo.updateOne(
                                { VendorID: record.VendorID },
                                { $set: { InitialSyncStatus: CurrentStage.INPROGRESS, AccountName: tempArr.AccountName } }
                            )
                        }
                        if (!vendorsInStack.includes(tempArr.VenderID)) {
                            if (!record) {
                                record = await this.AppleAccountRepo.create({
                                    AccountName: tempArr.AccountName,
                                    Issuer: tempArr.Issuer,
                                    KeyId: tempArr.KeyID,
                                    PrivateKey: tempArr.PrivateKey,
                                    VendorID: tempArr.VenderID,
                                    InitialSyncStatus: CurrentStage.INPROGRESS,
                                    SyncDate: new Date()
                                })
                            }
                            this.eventEmitter.emit('sync.Report', fromDate, toDate, record)
                            // this.eventEmitter.emit('sync.Report', fromDate, toDate, record)

                            // requestArr.push(this.doSyncReportInBatch(fromDate, toDate, recordTypeEnum.DOWNLOAD, record))
                            // requestArr.push(this.doSyncReportInBatch(fromDate, toDate, recordTypeEnum.SALES, record))
                            jsonRecords.push(record)
                            vendorsInStack.push(tempArr.VenderID)
                        }
                    }
                    // await Promise.all(requestArr)
                    console.log(requestArr, "reqqarrry>>>>>>>>>>>>>>>>>>");
                    resolve({ data: [], status: true })
                    fs.unlinkSync(file.path);
                }).on("error", () => {
                    resolve({ data: null, status: false })
                });
        })
        if (result.status == true) {
            return {
                data: await this.AppleAccountRepo.find({}, {
                    VendorID: true,
                    AccountName: true,
                }),
                status: true
            }
            // const data = await this.AppleAccountRepo.find({}, {
            //     VendorID: true,
            //     AccountName: true,
            // });

            // const updateResult = await this.AppleAccountRepo.updateMany(
            //     {},
            //     { $set: { InitialSyncStatus: CurrentStage.COMPLETED } }
            // );

            // return {
            //     data: data,
            //     status: true
            // }
        }

        if (result.status == false) {
            return result
        }
    }

    async doSyncReportBatch(from, to, type, applevendor = null) {
        let syncRecord = await this.analyticsReportRepo.aggregate([
            {
                $match: {
                    EventDate: {
                        $gte: new Date(new Date(from)),
                        $lte: new Date(new Date(to)),
                    },
                    type: type.toUpperCase(),
                },
            },
            {
                $group: {
                    _id: {
                        $dateToString: { format: "%Y-%m-%d", date: "$EventDate" }
                    },
                    doc: { $first: "$$ROOT" }
                }
            },
            {
                $replaceRoot: { newRoot: "$doc" }
            }
        ])
        return syncRecord
    }

    doFetchVendors = async () => {
        return {
            data: await this.AppleAccountRepo.find({}, {
                VendorID: true,
                AccountName: true
            }),
            status: true
        }
    }

    async doHandleDataExtractionFromZIP(FILE, hitDate, ReportTYPE, appleVendor = null): Promise<{
        status: boolean,
        count?: number,
        error?: any,
        data: any[]
    }> {
        const timestamp = moment().unix()
        const filePath = "public/tempReports/" + timestamp+ + '_sr.gz';
        fs.writeFileSync(filePath, FILE);
        const decompressedDataString = await zlib?.gunzipSync(FILE)?.toString('utf-8');
        return await new Promise(async (resolve, reject) => {
            parse(decompressedDataString, { delimiter: '\t' }, async (err, data) => {
                if (err) {
                    console.error(err);
                    resolve({ status: false, error: err, data: [], count: 0 })
                }
                let array = []
                let currencyRecord = await this.CurrencyValuationRepo.find()

                for (let index = 1; index < data.length; index++) {
                    const element = data[index];
                    let tempArr = {}
                    for (let jindex = 0; jindex < element.length; jindex++) {
                        const jElement = element[jindex];
                        tempArr[data[0][jindex].replace(/\s+/g, '')] = jElement
                    }
                    if (ReportTYPE == recordTypeEnum.SALES) {

                        //check the  customer  currency price 
                        // @ts-ignore
                        // if (tempArr?.CustomerPrice && tempArr?.CustomerCurrency.toLowerCase() == "usd" && tempArr?.CustomerPrice != "0.00") {
                        //     console.log('this if called curreecy is usd call the if........');

                        //     //@ts-ignore
                        //     let result = await this.analyticsService.doStoreICon(tempArr?.AppAppleID)
                        //     // // @ts-ignore
                        //     // let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: Number(tempArr?.CustomerPrice), type: ReportTYPE };

                        //     // if (!!appleVendor == true) {
                        //     //     obj.AccountID = appleVendor._id
                        //     // }

                        //     // if (result && result.data) {
                        //     //     obj.iconurl = result.data;
                        //     // }

                        //     // array.push(obj);
                        //     // second way to save data 
                        //     if (result && result?.data) {
                        //         // @ts-ignore
                        //         let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: Number(tempArr?.CustomerPrice), type: ReportTYPE, iconurl: result.data }
                        //         if (!!appleVendor == true) {
                        //             obj.AccountID = appleVendor._id
                        //         }
                        //         array.push(obj)

                        //     } else {
                        //         // @ts-ignore
                        //         let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: Number(tempArr?.CustomerPrice), type: ReportTYPE }
                        //         if (!!appleVendor == true) {
                        //             obj.AccountID = appleVendor._id
                        //         }
                        //         array.push(obj)
                        //     }

                        //     // first way to save data 
                        //     // @ts-ignore
                        //     // let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: Number(tempArr?.CustomerPrice), type: ReportTYPE, iconurl: result.data }
                        //     // if (!!appleVendor == true) {
                        //     //     obj.AccountID = appleVendor._id
                        //     // }
                        //     // array.push(obj)
                        // }
                        // // @ts-ignore
                        // if (tempArr?.CustomerPrice && tempArr?.CustomerPrice != "0.00" && tempArr?.CustomerPrice != "0.0" && tempArr?.CustomerCurrency !== "USD") {
                        //     console.log('this calles  currency is  not usd=======');

                        //     // @ts-ignore
                        //     // this.doGetUSDBaseValue(tempArr?.ProceedsCurrency, Number(tempArr?.DeveloperProceeds)).then((amount) => {
                        //     //     // @ts-ignore
                        //     //     if (amount.status == true) {
                        //     //         // @ts-ignore
                        //     //         let obj:AnalyticsReport={ ...tempArr,Units:Number(tempArr?.Units), EventDate: hitDate, DeveloperProceedsInUsd: amount?.value.toFixed(2), type: ReportTYPE }
                        //     //         if(!!appleVendor==true){
                        //     //             obj.AccountID=appleVendor._id
                        //     //         }
                        //     //         array.push(obj)
                        //     //     }
                        //     // }

                        //     let checkCurrency = currencyRecord.find((i) => i.currency === tempArr?.CustomerCurrency)
                        //     console.log(checkCurrency, '=============checkcurrency==============');




                        //     if (checkCurrency) {
                        //         // @ts-ignore
                        //         // let calculateCurrency = tempArr?.CustomerPrice / checkCurrency.rates
                        //         let calculateCurrency = Number(tempArr?.CustomerPrice) * Number(checkCurrency.rates);
                        //         // @ts-ignore
                        //         console.log(`${tempArr?.CustomerPrice} ${tempArr?.CustomerCurrency} = ${calculateCurrency.toFixed(2)} USD`);
                        //         console.log(calculateCurrency, 'calculateCurrency');

                        //         //@ts-ignore
                        //         let result = await this.analyticsService.doStoreICon(tempArr?.AppAppleID);
                        //         // //@ts-ignore
                        //         // let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: calculateCurrency.toFixed(2), type: ReportTYPE }


                        //         // if (!!appleVendor == true) {
                        //         //     obj.AccountID = appleVendor._id
                        //         // }

                        //         // if (result && result.data) {
                        //         //     obj.iconurl = result.data;
                        //         // }

                        //         // array.push(obj);

                        //         // second way to save data 
                        //         if (result && result?.data) {

                        //             console.log('if111111111111111111');

                        //             //@ts-ignore
                        //             let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: calculateCurrency.toFixed(2), type: ReportTYPE, iconurl: result.data }

                        //             if (!!appleVendor == true) {
                        //                 obj.AccountID = appleVendor._id
                        //             }
                        //             array.push(obj)
                        //         } else {
                        //             console.log('else111111111111111111111');

                        //             //@ts-ignore
                        //             let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: calculateCurrency.toFixed(2), type: ReportTYPE }

                        //             if (!!appleVendor == true) {
                        //                 obj.AccountID = appleVendor._id
                        //             }
                        //             array.push(obj)
                        //         }

                        //         // first way to save
                        //         // //@ts-ignore
                        //         // let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: calculateCurrency.toFixed(2), type: ReportTYPE, iconurl: result.data }

                        //         // if (!!appleVendor == true) {
                        //         //     obj.AccountID = appleVendor._id
                        //         // }
                        //         // array.push(obj)
                        //     }
                        // }

                        if (tempArr?.CustomerPrice && tempArr?.ProceedsCurrency.toLowerCase() == "usd" && tempArr?.DeveloperProceeds != "0.00") {
                            //@ts-ignore
                            let result = await this.analyticsService.doStoreICon(tempArr?.AppAppleID)

                            //@ts-ignore
                            let developerProceedsNum = Number(tempArr?.DeveloperProceeds);

                            // ✅ Condition: if CustomerPrice negative → make DeveloperProceeds negative
                            //@ts-ignore
                            if (Number(tempArr?.CustomerPrice) < 0) {
                                developerProceedsNum = -Math.abs(developerProceedsNum);
                            }
                            // // @ts-ignore
                            if (result && result?.data) {
                                // @ts-ignore
                                let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: developerProceedsNum, type: ReportTYPE, iconurl: result.data }
                                if (!!appleVendor == true) {
                                    obj.AccountID = appleVendor._id
                                }
                                array.push(obj)

                            } else {
                                // @ts-ignore
                                let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: developerProceedsNum, type: ReportTYPE }
                                if (!!appleVendor == true) {
                                    obj.AccountID = appleVendor._id
                                }
                                array.push(obj)
                            }
                        }
                        // @ts-ignore
                        if (tempArr?.CustomerPrice && tempArr?.DeveloperProceeds != "0.00" && tempArr?.DeveloperProceeds != "0.0" && tempArr?.ProceedsCurrency !== "USD") {
                            // @ts-ignore
                            let checkCurrency = currencyRecord.find((i) => i.currency === tempArr?.ProceedsCurrency)

                            if (checkCurrency) {
                                // @ts-ignore
                                // let calculateCurrency = tempArr?.CustomerPrice / checkCurrency.rates
                                let calculateCurrency = Number(tempArr?.DeveloperProceeds) * Number(checkCurrency.rates);
                                // @ts-ignore
                                // console.log(`${tempArr?.DeveloperProceeds} ${tempArr?.ProceedsCurrency} = ${calculateCurrency.toFixed(2)} USD`);

                                let developerProceedsNum = Number(calculateCurrency);

                                // ✅ Condition: if CustomerPrice negative → make DeveloperProceeds negative
                                //@ts-ignore
                                if (Number(tempArr?.CustomerPrice) < 0) {
                                    developerProceedsNum = -Math.abs(developerProceedsNum);
                                }

                                //@ts-ignore
                                let result = await this.analyticsService.doStoreICon(tempArr?.AppAppleID);
                                // //@ts-ignore
                                // second way to save data 
                                if (result && result?.data) {
                                    //@ts-ignore
                                    let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: developerProceedsNum.toFixed(2), type: ReportTYPE, iconurl: result.data }

                                    if (!!appleVendor == true) {
                                        obj.AccountID = appleVendor._id
                                    }
                                    array.push(obj)
                                } else {
                                    //@ts-ignore
                                    let obj: AnalyticsReport = { ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, CustomerProceedsInUsd: developerProceedsNum.toFixed(2), type: ReportTYPE }

                                    if (!!appleVendor == true) {
                                        obj.AccountID = appleVendor._id
                                    }
                                    array.push(obj)
                                }
                            }
                        }
                    } else if (ReportTYPE == recordTypeEnum.DOWNLOAD) {
                        //@ts-ignore
                        let result = await this.analyticsService.doStoreICon(tempArr?.AppleIdentifier)

                        // way to save data 
                        if (result && result?.data) {
                            // @ts-ignore
                            array.push({ ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, type: ReportTYPE, AccountID: appleVendor._id, iconurl: result.data })
                        } else {
                            // @ts-ignore
                            array.push({ ...tempArr, Units: Number(tempArr?.Units), EventDate: hitDate, type: ReportTYPE, AccountID: appleVendor._id })
                        }
                    }
                }
                resolve({ status: true, count: array?.length, data: array })
            }
            )
        })
    }
    async doGenerateTokenAPI({ iss, privateKey, keyId }) {
        try {
            // console.log(iss,'issississississ');
            // console.log(privateKey,'privateKeyprivateKeyprivateKeyprivateKey');
            // console.log(keyId,'keyIdkeyIdkeyId');

            return await lastValueFrom(
                this.httpService.post('http://localhost:3050/generate-token', {
                    iss: iss,
                    keyId: keyId,
                    privateKey: privateKey
                }).pipe(
                    map(response => response.data.access_token)
                )
            );
        } catch (error) {
            return {
                status: false,
                data: [],
                message: error.message,
                code: error.status,
                error: error?.response?.data
            }
        }
    }

    async doFetchReports(baseUrl, accountRecord = null) {
        const access_token = await this.doGenerateTokenAPI({
            iss: accountRecord?.Issuer, privateKey: accountRecord?.PrivateKey, keyId: accountRecord?.KeyId
        })
        if (!access_token) {
            console.error("❌ Invalid access token generated");
            return {
                status: false,
                code: 401,
                message: "Invalid or empty token",
            };
        }
        try {
            return await lastValueFrom(
                this.httpService.get(baseUrl, {
                    headers: {
                        'Accept': 'application/a-gzip',
                        'Authorization': `Bearer ${access_token}`
                    },
                    responseType: 'arraybuffer',
                }).pipe(
                    map(response => {
                        if (response.data) {
                            return {
                                status: true,
                                data: response.data,
                                code: response.status,
                                message: "Data Fetched!"
                            }
                        }
                    })));
        } catch (error) {
            // console.log("errror>>>>>>>>>>", baseUrl)
            // console.error("Error Message:", error.message);

            // if (error.response) {
            //     console.log(error.response, 'responseeeeeeeeeeeeeeeeeeeeee');
            //     console.error("Status:", error.response.status);
            //     console.error("Headers:", error.response.headers);
            //     console.error("Data:", error.response.data?.toString?.() || error.response.data);
            // }
            // return {
            //     status: false,
            //     data: [],
            //     message: error.message,
            //     code: error.response?.status,
            //     error: error?.response?.data
            // }

            if (error.response?.status === 404) {
                console.warn("📄 No data found for:", baseUrl);
                return {
                    status: false,
                    data: [],
                    message: error.message,
                    code: 404,
                    error: error?.response?.data, // skip gracefully
                };
            }
        }
    }
    generateJWT = async ({ privateKey,
        iss, KeyId }) => {
        const payload = { iss: iss, aud: process.env.audience };

        return {
            access_token: await this.jwtService.sign(payload, {
                header: {
                    alg: process.env.alg,
                    kid: KeyId
                },
                privateKey: privateKey
            })
        };
    }

    doGetReportsUrl(type = null, gDate, appleVendor) {
        if (!type && !gDate) {
            return null
        }
        const date = moment(gDate, this.APPLEDATEFORMAT)
        if (type == recordTypeEnum.DOWNLOAD) {
            return process.env.appleBaseUrl + process.env.salesReport + `?filter[frequency]=DAILY&filter[reportDate]=${date.format(this.APPLEDATEFORMAT)}&filter[reportSubType]=SUMMARY&filter[reportType]=SALES&filter[vendorNumber]=${appleVendor.VendorID}&filter[version]=1_0`
        }
        if (type == recordTypeEnum.SALES) {
            return process.env.appleBaseUrl + process.env.salesReport + `?filter[frequency]=DAILY&filter[reportDate]=${date.format(this.APPLEDATEFORMAT)}&filter[reportSubType]=DETAILED&filter[reportType]=SUBSCRIBER&filter[vendorNumber]=${appleVendor.VendorID}&filter[version]=1_3`
        }
    }

    // async convertCurrencyValue(from, to) {
    //     // const url = `https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/${from.toLowerCase()}/${to}.json`
    //     const url = `https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/${from.toLowerCase()}/${to.toLowerCase()}.json`;
    //     console.log("URL---", url)
    //     try {

    //         return await lastValueFrom(
    //             this.httpService.get(url).pipe(
    //                 map(async (response) => {
    //                     if (response.status == 200) {
    //                         return { status: true, value: response.data.usd, from, to, date: response.data.date }
    //                     }
    //                     else {
    //                         debugger
    //                     }
    //                     if (response.status !== 200) {
    //                         debugger
    //                     }
    //                 }),
    //             ),
    //         );
    //     }
    //     catch (error) {
    //         console.log("===============")
    //         console.log(error)
    //         console.log("===============")
    //     }
    // }



    // async convertCurrencyValue(from: string, to: string) {
    //     const fromLower = from.toLowerCase();
    //     const today = new Date().toISOString().split('T')[0];

    //     const primaryUrl = `https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@${today}/v1/currencies/${fromLower}.json`;
    //     const fallbackUrl = `https://${today}.currency-api.pages.dev/v1/currencies/${fromLower}.json`;

    //     const getRates = async (url: string) => {
    //         return await lastValueFrom(
    //             this.httpService.get(url).pipe(
    //                 timeout(8000),
    //                 map((res) => res.data),
    //                 catchError((err) => {
    //                     console.error(`Failed to fetch from ${url}:`, err.message);
    //                     return of(null); // fallback to null
    //                 })
    //             )
    //         );
    //     };

    //     const response = await getRates(primaryUrl) || await getRates(fallbackUrl);

    //     if (!response) {
    //         return { status: false, message: 'Both API URLs failed.' };
    //     }

    //     const rates = response[fromLower];
    //     const usdRate = rates?.usd;

    //     if (usdRate) {
    //         return {
    //             status: true,
    //             from,
    //             to,
    //             rate: usdRate,
    //             value: usdRate,
    //             date: response.date,
    //         };
    //     } else {
    //         return { status: false, message: `'usd' not found in ${fromLower}` };
    //     }
    // }

    // async convertCurrencyValue(from: string, to: string) {
    //     const fromLower = from.toLowerCase();
    //     const today = new Date().toISOString().split('T')[0];

    //     // const primaryUrl = `https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@${today}/v1/currencies/${fromLower}.json`;
    //     const primaryUrl =`https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/${fromLower}.json`;
    //     const fallbackUrl = `https://${today}.currency-api.pages.dev/v1/currencies/${fromLower}.json`;

    //     const getRates = async (url: string, label: string) => {
    //         try {
    //             const response = await lastValueFrom(
    //                 this.httpService.get(url).pipe(
    //                     timeout(50000), // 10 sec timeout
    //                     retryWhen(errors =>
    //                         errors.pipe(
    //                             delay(2000), // wait before retry
    //                             take(2), // max 2 retries
    //                         )
    //                     ),
    //                     map((res) => res.data),
    //                     catchError((err) => {
    //                         console.error(`❌ ${label} failed:`, err.message || err.code);
    //                         return of(null);
    //                     })
    //                 )
    //             );
    //             return response;
    //         } catch (e) {
    //             console.error(`🚨 Error during fetch from ${label}:`, e.message || e.code);
    //             return null;
    //         }
    //     };

    //     const response = await getRates(primaryUrl, "Primary URL") || await getRates(fallbackUrl, "Fallback URL");

    //     if (!response) {
    //         return { status: false, message: 'Both primary and fallback URLs failed to respond properly.' };
    //     }

    //     const rates = response[fromLower];
    //     const usdRate = rates?.usd;

    //     if (usdRate) {
    //         return {
    //             status: true,
    //             from,
    //             to,
    //             rate: usdRate,
    //             value: usdRate,
    //             date: response.date || today,
    //         };
    //     } else {
    //         return { status: false, message: `'usd' conversion rate not found in response.` };
    //     }
    // }

    async convertCurrencyValue(from: string, to: string) {
        const fromUpper = from.toUpperCase();
        const toUpper = to.toUpperCase();
        const today = new Date().toISOString().split('T')[0];

        const primaryUrl = `https://open.er-api.com/v6/latest/${fromUpper}`;

        const getRates = async (url: string, label: string) => {
            try {
                const response = await lastValueFrom(
                    this.httpService.get(url).pipe(
                        timeout(20000),
                        retryWhen(errors =>
                            errors.pipe(delay(2000), take(2))
                        ),
                        map(res => res.data),
                        catchError(err => {
                            console.error(`❌ ${label} failed:`, err.message || err.code);
                            return of(null);
                        })
                    )
                );
                return response;
            } catch (e) {
                console.error(`🚨 Error during fetch from ${label}:`, e.message || e.code);
                return null;
            }
        };

        const response = await getRates(primaryUrl, "Open ER API");

        if (!response || !response.rates) {
            return { status: false, message: 'API response is invalid or rates missing.' };
        }

        const rate = response.rates[toUpper];
        // console.log(`${fromUpper}-${rate}`,'rate');


        if (!rate) {
            return { status: false, message: `Conversion rate from ${fromUpper} to ${toUpper} not found.` };
        }

        return {
            status: true,
            from: fromUpper,
            to: toUpper,
            rate,
            value: rate,
            date: response.time_last_update_utc || today,
        };
    }

    enumerateDaysBetweenDates(startDate, endDate) {
        let dates = [];

        // const currDate = moment(startDate, "YYYY-MM-DD");

        // const lastDate = moment(endDate, "YYYY-MM-DD");

        // dates.push(currDate.clone().toDate())

        // console.log("DIFF",currDate.add(1, 'days').diff(lastDate) < 0)
        // while (currDate.add(1, 'days').diff(lastDate) < 0) {
        //     console.log(currDate.toDate());
        //     dates.push(currDate.clone().toDate());
        // }
        // dates.push(lastDate.clone().toDate())   

        const currDate = moment(startDate, "YYYY-MM-DD");
        const lastDate = moment(endDate, "YYYY-MM-DD");

        while (lastDate.diff(currDate) >= 0) {
            dates.push(moment(currDate).format("YYYY-MM-DD"));
            currDate.add(1, 'days');
        }
        return dates;
    };


    doGetUSDBaseValue = async (Currency, amount) => {
        let data = await this.CurrencyValuationRepo.findOne({ currency: Currency }).sort({ "createdAt": -1 }).limit(1).exec();

        if (data) {
            return { value: data.rates * amount, status: true }
        }
        return { value: null, status: false }
    }
}