import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as random_string from 'randomstring'
// import { ModelService } from 'src/model/model.service';

import { ConfigService } from '@nestjs/config';
import * as nodemailer from "nodemailer";
import * as bcrypt from 'bcrypt';
// import { log } from '@tensorflow/tfjs';
// import * as firebase from "firebase-admin";
import * as path from "path";
import * as fs from "fs";
import { Types } from 'mongoose'
import moment from 'moment';
import { ModelService } from '../model/model.service';
import * as firebase from "firebase-admin";

@Injectable()
export class CommonService {
    private nodemailer_email
    private nodemailer_password
    private server_key: string;
    private server: string;

    constructor(
        private readonly JwtService: JwtService,
        private readonly Model: ModelService,
        private readonly ConfigService: ConfigService
    ) {
        this.nodemailer_email = this.ConfigService.get<string>('NODEMAILER_MAIL')
        this.nodemailer_password = this.ConfigService.get<string>('NODEMAILER_PASSWORD')
        this.server = this.ConfigService.get<string>('SERVER')
        this.server_key = this.ConfigService.get<string>('NOTIFICATION_KEY')

        if (!firebase.apps.length) {
            // console.log("__dirname....", __dirname)
            // let file_path = path.resolve(__dirname, '../../assets/qixs-8ab6f-firebase-adminsdk-rb2vs-2075b4ba65.json');
            let file_path = path.resolve(__dirname, './assets/qixs-8ab6f-firebase-adminsdk-rb2vs-2075b4ba65.json');
            // console.log("file_path..11..", file_path)
            let parse_json = JSON.parse(fs.readFileSync(file_path, 'utf8'));
            // console.log("parse_json....", parse_json)
            // const serviceAccount = JSON.parse(fs.readFileSync('../../service_account.json', 'utf8'));
            firebase.initializeApp({
                credential: firebase.credential.cert(parse_json)
            });
        }
    }

    async generate_token(token_data: any) {
        try {
            let token = await this.JwtService.signAsync(token_data)
            return token;
        } catch (error) {
            throw new HttpException('invelid token', HttpStatus.BAD_REQUEST)
        }
    }

    async decode_token(token_data: any) {
        try {
            let token = await this.JwtService.verifyAsync(token_data)
            return token;
        } catch (error) {
            throw new HttpException('invelid token', HttpStatus.BAD_REQUEST)
        }
    }

    async set_options(pagination: number, limit: number) {
        try {
            // console.log("-=-=-pagination------",pagination,limit)
            let options: any = {
                lean: true,
                sort: { _id: -1 }
            }

            if (pagination == undefined && limit == undefined) {
                options = {
                    lean: true,
                    sort: { _id: -1 },
                    limit: 10,
                    pagination: 0,
                    skip: 0
                }
            }
            else if (pagination == undefined && typeof limit != undefined) {
                options = {
                    lean: true,
                    sort: { _id: -1 },
                    limit: Number(limit),
                    skip: 0,
                }
            }
            else if (typeof pagination != undefined && limit == undefined) {
                options = {
                    lean: true,
                    sort: { _id: -1 },
                    skip: Number(pagination) * Number(process.env.DEFAULT_LIMIT),
                    limit: Number(process.env.DEFAULT_LIMIT)
                }
            }
            else if (typeof pagination != undefined && typeof limit != undefined) {
                options = {
                    lean: true,
                    sort: { _id: -1 },
                    limit: Number(limit),
                    skip: Number(pagination) * Number(limit)
                }
            }
            return options
        }
        catch (err) {
            throw err;
        }
    }

    async encriptPass(pass: string) {
        try {
            const saltOrRounds = 10;
            const password = pass;
            return await bcrypt.hash(password, saltOrRounds);
        } catch (error) {
            throw error
        }
    }


    async bcriptPass(old_password, user_pass) {
        try {
            return await bcrypt.compare(old_password, user_pass);
        } catch (error) {
            throw error
        }
    }

    async GenerateOtp() {
        try {
            let options = {
                length: 4,
                charset: "123456789",
            };
            let code = random_string.generate(options);
            let otp = `${code}`;
            return otp;
        } catch (error) {
            throw error;
        }
    };

    // async verification(email: string, otp: any) {
    //     try {
    //         return await this.mailerService
    //             .sendMail({
    //                 to: `${email}`,
    //                 from: process.env.EMAIL,
    //                 subject: 'Verify User',
    //                 text: ` OTP :${otp}`
    //             });
    //     } catch (error) {
    //         throw error
    //     }
    // }


    async genUniqueCode(count: any) {
        try {
            let options = {
                length: 7,
                charset: "alphanumeric",
            };
            let random_value = random_string.generate(options);

            // fetch users count

            let inc_value = Number(count) + 1;

            // unique code
            let unique_code = `${random_value}${inc_value}`;
            return unique_code;
        } catch (err) {
            throw err;
        }
    };

    async genSecretKey(count: any) {
        try {
            let options = {
                length: 15,
                charset: "alphanumeric",
            };
            let random_value =await random_string.generate(options);

            let unique_code = `${"secret_"}${random_value}${count}`;
            return unique_code;
        } catch (err) {
            throw err;
        }
    };

    async skip_data(payload_data: any) {
        try {
            let { pagination, limit }: any = payload_data
            let set_pagination: number = 0, set_limit: number = 0;

            if (pagination != undefined) { set_pagination = parseInt(pagination) }
            if (limit != undefined) { set_limit = parseInt(limit) }
            return {
                $skip: set_pagination * set_limit
            }
        }
        catch (err) {
            throw err;
        }
    }

    async limit_data(payload_data: any) {
        try {

            let { limit }: any = payload_data
            let set_limit: number = 50;
            if (limit != undefined) { set_limit = parseInt(limit) }
            return {
                $limit: set_limit
            }

        }
        catch (err) {
            throw err;
        }

    }

    async create_vendor_session(body: any, token_data: any, authorization: string) {
        try {
            let { fcm_token } = body
            let { _id: vendor_id, token_gen_at } = token_data
            let data_to_save: any = {
                vendor_id: new Types.ObjectId(vendor_id),
                type: 'VENDOR',
                token_gen_at: token_gen_at,
                authorization: authorization
            }
            if (!!fcm_token) {
                data_to_save.fcm_token = fcm_token
            }
            return this.Model.SessionModel.create(data_to_save)
        } catch (error) {
            throw error
        }
    }

    async create_admin_session(body: any, token_data: any, authorization: string) {
        try {
            // console.log("authorization.....", authorization);
            // console.log("token_data.....", token_data);

            let { fcm_token, device_type } = body
            let { _id: admin_id, token_gen_at } = token_data
            let data_to_save: any = {
                admin_id: admin_id,
                // type: 'ADMIN',
                token_gen_at: token_gen_at,
                device_type: device_type,
                access_token: authorization
            }
            if (!!fcm_token) {
                data_to_save.fcm_token = fcm_token
            }
            return this.Model.SessionModel.create(data_to_save)
        } catch (error) {
            throw error
        }
    }

    async filter_null_values_objects(object: object) {
        try {
            const filteredObject = Object.fromEntries(Object.entries(object).filter(([key, value]) => value !== null));
            return filteredObject
        } catch (error) {
            throw error
        }
    }

    async send_email(email: any, subject: any, html: any) {
        try {

            const MAIL_SETTINGS = {
                service: "gmail",
                auth: {
                    user: this.nodemailer_email,
                    pass: this.nodemailer_password
                }
            }
            // var transport = nodemailer.createTransport(MAIL_SETTINGS);
            var transport = nodemailer.createTransport({
                host: "smtp.zeptomail.in",
                port: 587,
                auth: {
                    user: "emailapikey",
                    pass: this.nodemailer_password
                }
            });
            let mailoption = {
                from: `Qixs ${this.nodemailer_email}`,
                to: email,
                subject: subject,
                // text: text,
                html: html
            }
            transport.sendMail(mailoption, function (error, info) {
                if (error) {
                    console.log("-=-=-errrrrr----------", error);
                } else {
                    console.log("Email is sent ", info);
                }
            })
        } catch (err) {
            return err
        }
    }

    async send_bulk_emails(recipients: string[], subject: string, html: any) {
        try {
            const transporter = nodemailer.createTransport({
                host: "smtp.zeptomail.in",
                port: 587,
                auth: {
                    user: "emailapikey",
                    pass: this.nodemailer_password
                }
            });
    
            const mailOptions = {
                from: `qixs.ai ${this.nodemailer_email}`,
                subject: subject,
                html: html
            };
    
            const emailPromises = recipients.map((email) => {
                return transporter.sendMail({
                    ...mailOptions,
                    to: email,
                }).then(() => {
                    console.log(`Email sent to: ${email}`);
                }).catch((error) => {
                    console.error(`Error sending email to ${email}:`, error);
                });
            });
    
            await Promise.all(emailPromises);
        } catch (err) {
            console.error("Error in send_bulk_emails:", err);
            throw err;
        }
    }
    

    async send_email_driver(email: any, subject: any, html: any, pass: any) {
        try {
            if (this.server == 'LIVE') {
                const transport = nodemailer.createTransport({
                    host: "smtp.zeptomail.in",
                    port: 465,
                    secure: true,
                    auth: {
                        user: "emailapikey",
                        pass: this.nodemailer_password
                    }
                });
                // console.log("transport.....", transport);

                const mailoption = {
                    from: `Abundish<${this.nodemailer_email}>`,
                    to: email,
                    subject: subject,
                    password: pass,
                    html: html
                };
                // console.log("mailoption", mailoption);

                transport.sendMail(mailoption, function (error, info) {
                    if (error) {
                        // console.log("-=-=-errrrrr----------", error);
                    } else {
                        console.log("Email is sent ", info);
                    }
                })
            }
            else {
                // console.log("email------------->", email);
                // console.log("email------------->", subject);
                // console.log("pass1111------------->", pass);

                // console.log("pass......", this.nodemailer_password);
                // console.log("email......", this.nodemailer_email);
                const MAIL_SETTINGS = {
                    service: "gmail",
                    auth: {
                        user: this.nodemailer_email,
                        pass: this.nodemailer_password
                    }
                }
                //console.log("emaildetails-=-=-=-=-=--==--=",MAIL_SETTINGS)
                var transport = nodemailer.createTransport(MAIL_SETTINGS);
                // console.log("transport.....");
                // const { email, subject, text, html } = data
                let mailoption = {
                    from: this.nodemailer_email,
                    to: email,
                    subject: subject,
                    // text: text,
                    html: html
                }
                transport.sendMail(mailoption, function (error, info) {
                    if (error) {
                        console.log("-=-=-errrrrr----------", error);
                    } else {
                        console.log("Email is sent ", info);
                    }
                })
            }

            ///............................

        } catch (err) {
            return err
        }
    }

    async authorization_decode(req: any) {
        try {
            const token = req.headers.authorization
            // console.log('token,token', token);
            if (!!token) {
                let new_token = token.split(' ')[1]
                const payload = await this.JwtService.decode(new_token)
                let { scope, _id } = payload
                // console.log('payload', payload);
                // let user_data= await this.model.userModel.find({_id:_id})
                return _id
            }
        } catch (error) {
            throw error
        }
    }

    async socket_token_decode(token: any) {
        try {

            // const token = req.headers.authorization;
            // console.log('token,token', token);

            if (!!token) {
                // let new_token = token.split(' ')[1]
                const payload = await this.JwtService.verifyAsync(token, { secret: 'admin_super_seckret_key' })
                let { scope, _id } = payload
                // console.log('payload', payload);
                // let user_data= await this.model.userModel.find({_id:_id})
                return _id
            }
        } catch (error) {
            throw error
        }
    }

    // async genrate_product_id() {
    //     try {
    //         let static_value = "PRODU";
    //         let options = {
    //             length: 4,
    //             charset: "alphanumeric",
    //             capitalization: "uppercase",
    //         };
    //         let random_value = random_string.generate(options);
    //         // fetch ORDERS count
    //         let count_orders = await this.Model.productModel.countDocuments({})
    //         let unique_id = Number(count_orders) + 1;
    //         let order_id = `${static_value}${random_value}${unique_id}`;
    //         return order_id;
    //     } catch (err) {
    //         throw err;
    //     }
    // };

    // send_silent_notification = async (fcm_token: string, notification_data: any) => {
    //     try {
    //         console.log("fcm_token....", fcm_token);
    //         let { title, message, image_url, sender_id, call_type, name } = notification_data;

    //         const notification_payload: any = {
    //             data: {
    //                 title: title,
    //                 message: message,
    //                 // sender_id:sender_id,
    //                 // call_type: call_type,
    //                 // name: name,
    //             },
    //             token: fcm_token,
    //             android: {
    //                 priority: 'high'
    //             },
    //             apns: {
    //                 payload: {
    //                     aps: {
    //                         contentAvailable: true
    //                     }
    //                 }
    //             }
    //         };
    //         // if(!!image_url){notification_payload.data.image_url = null}
    //         // console.log("notification_payload....", notification_payload);
    //         firebase.messaging().send(notification_payload)
    //             .then(response => {
    //                 console.log('Notification sent...', response);
    //             })
    //             .catch(error => {
    //                 console.error('Failed to send notification...', error);
    //             });
    //     }
    //     catch (error) {
    //         // console.log("generate_push...err", error);
    //         throw error;
    //     }
    // }

    // send_notification = async (fcm_token: string, notification_data: any) => {
    //     try {
    //         console.log("fcm_token....", fcm_token);
    //         let { title, message, image_url, sender_id, call_type, name } = notification_data;

    //         const notification_payload: any = {
    //             data: {
    //                 title: title,
    //                 message: message,
    //                 // sender_id:sender_id,
    //                 // call_type: call_type,
    //                 // name: name,
    //             },
    //             notification: {
    //                 title: title,
    //                 body: message,
    //             },
    //             token: fcm_token,
    //             android: {
    //                 priority: 'high'
    //             },
    //             apns: {
    //                 payload: {
    //                     aps: {
    //                         contentAvailable: true
    //                     }
    //                 }
    //             }
    //         };
    //         // if(!!image_url){notification_payload.data.image_url = null}
    //         // console.log("notification_payload....", notification_payload);
    //         firebase.messaging().send(notification_payload)
    //             .then(response => {
    //                 console.log('Notification sent...', response);
    //             })
    //             .catch(error => {
    //                 console.error('Failed to send notification...', error);
    //             });
    //     }
    //     catch (error) {
    //         // console.log("generate_push...err", error);
    //         throw error;
    //     }
    // }

    // send_notification_to_all = async (fcm_tokens: any, notification_data: any) => {
    //     try {
    //         // console.log("fcm_token....", fcm_tokens);
    //         let { title, message, image_url, sender_id, call_type, name } = notification_data;

    //         // console.log("notification_data", notification_data);
    //         if (!fcm_tokens.length) {
    //             return null
    //         }
    //         firebase.messaging().sendEachForMulticast({
    //             data: {
    //                 title: title,
    //                 message: JSON.stringify(notification_data), // Send the entire data object as a string
    //             },
    //             notification: {
    //                 title: title,
    //                 body: message,
    //             },
    //             tokens: fcm_tokens,
    //             //     tokens:[
    //             //   "dpahZrrQR22dvEkn1Aj283:APA91bGmuPntd9HMz5CmHV-b3kuZvZnEIz3e3A3J_OY0zXzSx0307NV7_vij6MKTi-PhSBvyzJKhSAk-8CSPRc25_mk7A3hoVZDA-Qc7tGz1bwGSIsrors0_MduKIB02QW1bjUlHG2bs"],
    //             android: {
    //                 priority: 'high'
    //             },
    //             apns: {
    //                 payload: {
    //                     aps: {
    //                         contentAvailable: true
    //                     }
    //                 }
    //             }
    //         }).then(response => {
    //             console.log('Notification sent...', response);
    //             for (let i = 0; i < response?.responses?.length; i++) {
    //                 const element = response?.responses[i];
    //                 console.log(element);

    //             }
    //         })
    //             .catch(error => {
    //                 console.error('Failed to send notification...', error);
    //             });

    //     }
    //     catch (error) {
    //         // console.log("generate_push...err", error);
    //         throw error;
    //     }
    // }

    // send_silent_notification_to_all = async (fcm_tokens: any, notification_data: any) => {
    //     try {
    //         // console.log("fcm_token....", fcm_tokens);
    //         let { title, message, image_url, sender_id, call_type, name } = notification_data;

    //         // console.log("notification_data", notification_data);
    //         if (!fcm_tokens.length) {
    //             return null
    //         }
    //         firebase.messaging().sendEachForMulticast({
    //             data: {
    //                 title: title,
    //                 message: JSON.stringify(notification_data), // Send the entire data object as a string
    //             },
    //             tokens: fcm_tokens,
    //             //     tokens:[
    //             //   "dpahZrrQR22dvEkn1Aj283:APA91bGmuPntd9HMz5CmHV-b3kuZvZnEIz3e3A3J_OY0zXzSx0307NV7_vij6MKTi-PhSBvyzJKhSAk-8CSPRc25_mk7A3hoVZDA-Qc7tGz1bwGSIsrors0_MduKIB02QW1bjUlHG2bs"],
    //             android: {
    //                 priority: 'high'
    //             },
    //             apns: {
    //                 payload: {
    //                     aps: {
    //                         contentAvailable: true
    //                     }
    //                 }
    //             }
    //         }).then(response => {
    //             console.log('Notification sent...', response);
    //             for (let i = 0; i < response?.responses?.length; i++) {
    //                 const element = response?.responses[i];
    //                 console.log(element);

    //             }
    //         })
    //             .catch(error => {
    //                 console.error('Failed to send notification...', error);
    //             });

    //     }
    //     catch (error) {
    //         // console.log("generate_push...err", error);
    //         throw error;
    //     }
    // }


    generate_otp = async () => {
        try {
            let options = {
                length: 4,
                charset: '123456789'
            }
            let code = random_string.generate(options)
            return code
        }
        catch (err) {
            throw err;
        }
    }

    user_subscription_velidation_pickup_order = async (user_id: any) => {
        try {
            let user_detail: any = await this.Model.UserModel.find({ _id: new Types.ObjectId(user_id) }, { __v: 0 }, { lean: true })

            if (user_detail.length) {
                return user_detail[0].pickup_order_limit_left ? true : false
            }
            return false
        }
        catch (err) {
            throw err;
        }
    }

    // this_month_order_counts_pickup = async (user_id: any) => {
    //     try {
    //         let start_of_month = moment().startOf('month').valueOf()
    //         let end_of_month = moment().endOf('month').valueOf()

    //         let orders = await this.Model.orderModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 delivery_type: 'PICKUP',
    //                 created_at: {
    //                     $gte: start_of_month,
    //                     $lte: end_of_month
    //                 }
    //             },
    //             {},
    //             {}
    //         )
    //         return orders.length
    //     } catch (error) {
    //         throw error
    //     }
    // }

    // this_month_order_counts_delivery = async (user_id: any, order_id?: any) => {
    //     try {
    //         let start_of_month = moment().startOf('month').valueOf()
    //         let end_of_month = moment().endOf('month').valueOf()

    //         let orders = await this.Model.orderModel.find(
    //             {
    //                 ...(order_id && { _id: new Types.ObjectId(order_id) }),
    //                 user_id: new Types.ObjectId(user_id),
    //                 delivery_type: 'DELIVERY',
    //                 created_at: {
    //                     $gte: start_of_month,
    //                     $lte: end_of_month
    //                 }
    //             },
    //             {},
    //             {}
    //         )
    //         return orders.length
    //     } catch (error) {
    //         throw error
    //     }
    // }

    // this_month_order_plan_type_platinum = async (user_id: any, order_id?: any) => {
    //     try {

    //         let data: any = await this.Model.subscriptionModel.find({ user_id: new Types.ObjectId(user_id), is_cancel: false, is_expire: false }, { __v: 0 }, { lean: true }).populate([{ path: 'plan_id' }])
    //         let start_of_month = 0
    //         let end_of_month = 0
    //         if (data[0]?.plan_id?.name == 'platinum') {
    //             start_of_month = data[0].start_date
    //             end_of_month = data[0].expire_date
    //         }
    //         // console.log("start_of_month", moment(start_of_month).format());
    //         // console.log("end_of_month", moment(end_of_month).format());

    //         let orders = await this.Model.orderModel.find(
    //             {
    //                 ...(order_id && { _id: { $ne: new Types.ObjectId(order_id) } }),
    //                 user_id: new Types.ObjectId(user_id),
    //                 delivery_type: 'DELIVERY',
    //                 created_at: {
    //                     $gte: start_of_month,
    //                     $lte: end_of_month
    //                 }
    //             },
    //         )
    //         return orders.length
    //     } catch (error) {
    //         throw error
    //     }
    // }

    // is_user_has_platinum_plan = async (user_id: any) => {
    //     try {
    //         let subscription: any = await this.Model.subscriptionModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 is_cancel: false,
    //                 is_expire: false
    //             }, { __v: 0 }, { lean: true }).populate([{ path: 'plan_id' }])
    //         console.log("subscription", subscription);

    //         let plan = false
    //         if (subscription[0]?.plan_id?.name == 'platinum') {
    //             plan = true
    //         }
    //         return plan
    //     }
    //     catch (err) {
    //         throw err;
    //     }
    // }


    // total_amount_order_this_month = async (user_id: any) => {
    //     try {
    //         let start_of_month = moment().startOf('month').valueOf()
    //         let end_of_month = moment().endOf('month').valueOf()

    //         let orders = await this.Model.orderModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 created_at: {
    //                     $gte: start_of_month,
    //                     $lte: end_of_month
    //                 }
    //             },
    //             {},
    //             { lean: true }
    //         )
    //         let total_amount = 0
    //         for (let i = 0; i < orders.length; i++) {
    //             let { coupon_discount, total_prices } = orders[i];
    //             let amount = total_prices
    //             if (coupon_discount) amount - coupon_discount
    //             total_amount += amount
    //         }
    //         return total_amount
    //     } catch (error) {
    //         throw error
    //     }
    // }


    // total_amount_order_this_month_according_to_subscription = async (user_id: any) => {
    //     try {
    //         let start_of_month = moment().startOf('month').valueOf()
    //         let end_of_month = moment().endOf('month').valueOf()
    //         let data = await this.Model.subscriptionModel.find({ user_id: new Types.ObjectId(user_id), is_cancel: false, is_expire: true }, {}, { lean: true })
    //         if (data.length) {
    //             start_of_month = data[0].start_date
    //             end_of_month = data[0].expire_date
    //         }
    //         let orders = await this.Model.orderModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 created_at: {
    //                     $gte: start_of_month,
    //                     $lte: end_of_month
    //                 }
    //             },
    //             {},
    //             { lean: true }
    //         )
    //         let total_amount = 0
    //         for (let i = 0; i < orders.length; i++) {
    //             let { coupon_discount, total_prices } = orders[i];
    //             let amount = total_prices
    //             if (coupon_discount) amount - coupon_discount
    //             total_amount += amount
    //         }
    //         return total_amount
    //     } catch (error) {
    //         throw error
    //     }
    // }





    // user_subscription_velidation_order_amount_limit = async (user_id: any) => {
    //     try {
    //         let subscription: any = await this.Model.subscriptionModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 is_cancel: false,
    //                 is_expire: false
    //             }, { __v: 0 }, { lean: true }).populate([{ path: 'plan_id' }])


    //         let membership: any = await this.Model.user_membershipModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 is_cancel: false,
    //                 is_expire: false
    //             }, { __v: 0 }, { lean: true }).populate([{ path: 'membership_id' }])

    //         let total_order_amount = await this.total_amount_order_this_month_according_to_subscription(user_id)
    //         let order_limit_reach = false

    //         if (!membership.length && !subscription.length) {
    //             return true
    //         }
    //         let user_data: any = await this.Model.UserModel.findOne({ _id: new Types.ObjectId(user_id) }, { __v: 0 }, { lean: true })

    //         let user_amount_has = user_data?.order_amount_limit_left || 0

    //         if (total_order_amount >= user_amount_has) {
    //             order_limit_reach = true
    //         }
    //         return order_limit_reach
    //     }
    //     catch (err) {
    //         throw err;
    //     }
    // }


    // user_order_amount_limit_left = async (user_id: any) => {
    //     try {
    //         let subscription: any = await this.Model.subscriptionModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 is_cancel: false,
    //                 is_expire: false
    //             }, { __v: 0 }, { lean: true }).populate([{ path: 'plan_id' }])

    //         let membership: any = await this.Model.user_membershipModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 is_cancel: false,
    //                 is_expire: false
    //             }, { __v: 0 }, { lean: true }).populate([{ path: 'membership_id' }])

    //         let total_order_amount = await this.total_amount_order_this_month(user_id)
    //         let order_limit = 0

    //         if (!membership.length && !subscription.length) {
    //             return 0
    //         }


    //         let user_amount_has = subscription[0]?.plan_id?.amount ? subscription[0]?.plan_id?.amount : membership[0]?.membership_id?.amount ? membership[0]?.membership_id?.amount : 0

    //         order_limit = user_amount_has - total_order_amount

    //         // if (subscription[0]?.plan_id?.name == 'silver') {
    //         //     order_limit = 2000 - total_order_amount
    //         // } else if (subscription[0]?.plan_id?.name == 'gold') {
    //         //     order_limit = 6000 - total_order_amount
    //         // } else if (subscription[0]?.plan_id?.name == 'platinum') {
    //         //     order_limit = 10000 - total_order_amount
    //         // }

    //         return order_limit > 0 ? order_limit : 0
    //     }
    //     catch (err) {
    //         throw err;
    //     }
    // }

    // user_points = async (user_id: any) => {
    //     try {
    //         let points_data = await this.Model.pointsModel.aggregate(
    //             [
    //                 {
    //                     $match: {
    //                         user_id: new Types.ObjectId(user_id),
    //                         is_expire: false
    //                     }
    //                 },
    //                 {
    //                     $group: {
    //                         _id: null,
    //                         total_points: { $sum: "$points" }
    //                     }
    //                 }
    //             ]
    //         )
    //         return points_data.length ? points_data[0].total_points : 0
    //     }
    //     catch (err) {
    //         throw err;
    //     }
    // }

    // membership_order_amount = async (user_id: any) => {
    //     try {
    //         let start_of_month = moment().startOf('month').valueOf()
    //         let end_of_month = moment().endOf('month').valueOf()
    //         let data = await this.Model.user_membershipModel.find({ user_id: new Types.ObjectId(user_id), is_cancel: false, is_expire: false }, {}, { lean: true })
    //         if (data.length) {
    //             start_of_month = data[0].start_date
    //             end_of_month = data[0].expire_date
    //         }
    //         let orders = await this.Model.orderModel.find(
    //             {
    //                 user_id: new Types.ObjectId(user_id),
    //                 order_status: { $ne: "CANCELLED" },
    //                 payment_status: "SUCCESS",
    //                 created_at: {
    //                     $gte: start_of_month,
    //                     $lte: end_of_month
    //                 }
    //             },
    //             {},
    //             { lean: true }
    //         )
    //         let total_amount = 0
    //         for (let i = 0; i < orders.length; i++) {
    //             let { coupon_discount, total_prices } = orders[i];
    //             let amount = total_prices
    //             if (coupon_discount) amount - coupon_discount
    //             total_amount += amount
    //         }
    //         return total_amount
    //     } catch (error) {
    //         throw error
    //     }
    // }


    fetch_user_token = async (user_id: string) => {
        try {
            let user_data = await this.Model.UserModel.findById(new Types.ObjectId(user_id))
            // if (!user_data?.is_notification_visable) {
            //     return []
            // }
            let query = {
                user_id: new Types.ObjectId(user_id),
                fcm_token: { $ne: null }
            }

            let projection = { __v: 0 }
            let options = { lean: true, _id: -1 }
            let find = await this.Model.SessionModel.find(query, projection, options);
            let fcm_tokens = [];
            if (find.length > 0) {
                for (let i = 0; i < find.length; i++) {
                    fcm_tokens.push(find[i].fcm_token)
                }
            }
            let new_arr = [...new Set(fcm_tokens)];

            return new_arr;
        }
        catch (err) {
            throw err;
        }
    }

    fetch_driver_token = async (driver_id: string) => {
        try {
            let query = {
                driver_id: new Types.ObjectId(driver_id),
                fcm_token: { $ne: null }
            }

            let projection = { __v: 0 }
            let options = { lean: true, _id: -1 }
            let find = await this.Model.SessionModel.find(query, projection, options);
            let fcm_tokens = [];
            if (find.length > 0) {
                for (let i = 0; i < find.length; i++) {
                    fcm_tokens.push(find[i].fcm_token)
                }
            }
            let new_arr = [...new Set(fcm_tokens)];

            return new_arr;
        }
        catch (err) {
            throw err;
        }
    }

    fetch_seller_token = async (seller_id: string) => {
        try {
            let query = {
                seller_id: new Types.ObjectId(seller_id),
                fcm_token: { $ne: null }
            }

            let projection = { __v: 0 }
            let options = { lean: true, _id: -1 }
            let find = await this.Model.SessionModel.find(query, projection, options);
            let fcm_tokens = [];
            if (find.length > 0) {
                for (let i = 0; i < find.length; i++) {
                    fcm_tokens.push(find[i].fcm_token)
                }
            }
            let new_arr = [...new Set(fcm_tokens)];

            return new_arr;
        }
        catch (err) {
            throw err;
        }
    }

    fetch_agent_token = async (agent_id: string) => {
        try {
            let query = {
                agent_id: new Types.ObjectId(agent_id),
                fcm_token: { $ne: null }
            }

            let projection = { __v: 0 }
            let options = { lean: true, _id: -1 }
            let find = await this.Model.SessionModel.find(query, projection, options);
            let fcm_tokens = [];
            if (find.length > 0) {
                for (let i = 0; i < find.length; i++) {
                    fcm_tokens.push(find[i].fcm_token)
                }
            }
            let new_arr = [...new Set(fcm_tokens)];

            return new_arr;
        }
        catch (err) {
            throw err;
        }
    }
    fetch_chef_token = async (chef_id: string) => {
        try {
            let query = {
                chef_id: new Types.ObjectId(chef_id),
                fcm_token: { $ne: null }
            }

            let projection = { __v: 0 }
            let options = { lean: true, _id: -1 }
            let find = await this.Model.SessionModel.find(query, projection, options);
            let fcm_tokens = [];
            if (find.length > 0) {
                for (let i = 0; i < find.length; i++) {
                    fcm_tokens.push(find[i].fcm_token)
                }
            }
            let new_arr = [...new Set(fcm_tokens)];

            return new_arr;
        }
        catch (err) {
            throw err;
        }
    }


    fetch_farmer_token = async (farmer_id: string) => {
        try {
            let query = {
                farmer_id: new Types.ObjectId(farmer_id),
                fcm_token: { $ne: null }
            }

            let projection = { __v: 0 }
            let options = { lean: true, _id: -1 }
            let find = await this.Model.SessionModel.find(query, projection, options);
            let fcm_tokens = [];
            if (find.length > 0) {
                for (let i = 0; i < find.length; i++) {
                    fcm_tokens.push(find[i].fcm_token)
                }
            }
            let new_arr = [...new Set(fcm_tokens)];

            return new_arr;
        }
        catch (err) {
            throw err;
        }
    }

    fetch_admin_token = async (admin_id: string) => {
        try {
            let query = {
                admin_id: new Types.ObjectId(admin_id),
                fcm_token: { $ne: null }
            }

            let projection = { __v: 0 }
            let options = { lean: true, _id: -1 }
            let find = await this.Model.SessionModel.find(query, projection, options);
            let fcm_tokens = [];
            if (find.length > 0) {
                for (let i = 0; i < find.length; i++) {
                    fcm_tokens.push(find[i].fcm_token)
                }
            }
            let new_arr = [...new Set(fcm_tokens)];

            return new_arr;
        }
        catch (err) {
            throw err;
        }
    }


    send_notification_to_all = async (fcm_tokens: any, notification_data: any) => {
        try {
            let { title, message, image_url, sender_id, call_type, name } = notification_data;

            if (!fcm_tokens.length) {
                return null
            }
            firebase.messaging().sendEachForMulticast({
                data: {
                    title: title,
                    message: JSON.stringify(notification_data),
                },
                notification: {
                    title: title,
                    body: message,
                },
                tokens: fcm_tokens,
                android: {
                    priority: 'high'
                },
                apns: {
                    payload: {
                        aps: {
                            contentAvailable: true
                        }
                    }
                }
            }).then(response => {
                console.log('Notification sent...', response);
                for (let i = 0; i < response?.responses?.length; i++) {
                    const element = response?.responses[i];
                    console.log(element);

                }
            })
                .catch(error => {
                    console.error('Failed to send notification...', error);
                });

        }
        catch (error) {
            // console.log("generate_push...err", error);
            throw error;
        }
    }
}
