import { Injectable, HttpException, HttpStatus, Res, Inject, OnModuleInit } from "@nestjs/common"
import { InjectRepository } from "@nestjs/typeorm"
import { Repository, Like, Not, ILike, Brackets } from "typeorm"
import { classToPlain } from "class-transformer"
const moment = require('moment');

// Entities Files
import * as ExcelJS from 'exceljs';
import { CampaignRepository } from "src/modules/campaign/campaign.repository"
import { Campaign } from "src/entities/campaign.entity"
import { Users } from "src/entities/users.entity"
import { responseMessages } from "src/messages/response-messages"
import { CampaignPayment, PAYMENT_STATUS } from "src/entities/campaign_payment.entity"
import { CampaignPaymentHistory, PAYMENT_STATUS as PaymentType } from "src/entities/campaign_payment_history.entity"
import { Posts } from "src/entities/posts.entity";
import { CampaignRecommended } from "src/entities/campaign_recommended.entity";
import { notificationMessages } from "src/messages/notifications-messages";
import { RedirectType } from "src/entities/notifications.entity";
import * as sgClient from '@sendgrid/client';
import { EncryptionService } from "src/common/services/encryption/encryption.service";
import { CommonService } from "src/modules/common/common.services";
import * as csv from 'csv-parser';
import { Readable } from 'stream';
import { send } from "process";
// DTO Files

@Injectable()
export class MarketingCampaignService implements OnModuleInit {
    constructor(
        private readonly encryptionService: EncryptionService,
        private readonly commonService: CommonService,
    ) {

    }
    async onModuleInit() {
        const password = await this.encryptionService.decrypt(process.env.MAIL_PASSWORD);
        console.log(password);
        sgClient.setApiKey(password);
    }


    async createCampaign(body: any) {

        let request = {
            url: `/v3/marketing/singlesends`,
            method: 'POST',
            body,
        };

        if (body?.id) {
            request = {
                url: `/v3/marketing/singlesends/${body.id}`,
                method: 'PATCH',
                body,
            };
        }

        try {
            const [response]: any = await sgClient.request(request as any);
            await this.scheduleCampaign({ "send_at": "now" }, { id: response?.body?.id });
            return response.body;

        } catch (err) {
            console.log(err.response.body.errors[0]);
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async scheduleCampaign(body: any, param: any) {
        const request = {
            url: `/v3/marketing/singlesends/${param.id}/schedule`,
            method: 'PUT',
            body: {
                "send_at": body.send_at,
                "status": "scheduled"
            },
        };
        try {
            const [response]: any = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            console.log(err);
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async testMail(body: any) {
        const { email, subject, html_content } = body;
        const payload = {
            personalizations: [{ to: email.map((email: any) => ({ email: email })) }],
            from: { email: process.env.MAIL_FROM_ADDRESS, name: process.env.MAIL_FROM_NAME },
            subject: subject,
            content: [{ type: 'text/html', value: html_content }],
        };

        const request = {
            url: `/v3/mail/send`,
            method: 'POST',
            body: payload,
        };
        try {
            const [response]: any = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            console.log(err);
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async getCampaigns(body) {
        const queryParams = { page_size: 50, page_token: body.nextPageToken || '' };
        const request = {
            url: `/v3/marketing/singlesends/search`,
            method: 'POST',
            body,
            qs: queryParams,
        };
        try {
            const [response]: any = await sgClient.request(request as any);
            const nextUrl = response.body._metadata?.next;
            const nextPageToken = nextUrl?.match(/page_token=([^&]+)/)?.[1];
            return { data: response.body, nextPageToken: nextPageToken ?? null };
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async getCampaignDetails(body) {

        const details = {
            url: `/v3/marketing/singlesends/${body.id}`,
            method: 'GET',
        };

        try {
            const [response]: any = await sgClient.request(details as any);
            const resp = response.body;
            let statsResp = null;
            if (resp.status === 'triggered') {
                const stats = {
                    url: `/v3/marketing/stats/singlesends/${body.id}`,
                    method: 'GET',
                };
                const [statsResponse]: any = await sgClient.request(stats as any);
                if (statsResponse?.body?.results?.length > 0) {
                    statsResp = statsResponse?.body?.results[0];
                }
            }
            return { details: resp, stats: statsResp };
        } catch (err) {
            throw new HttpException(responseMessages.en.marketing_campaign.detail_not_exists, 500);
        }
    }

    async deleteCampaign(body) {
        const request = {
            url: `/v3/marketing/singlesends/${body.id}`,
            method: 'DELETE',
        };
        try {
            const [response]: any = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async crateListing(body: any) {
        let { groupId, name, fileName } = body;

        if (!groupId) {
            const group: any = await this.createGroup(name);
            groupId = group.id;
        }

        let chunks = [];
        //  if (fileName.containing('.csv')) {
        chunks = await this.parseCSVBuffer(fileName);
        // } else {
        //     chunks = await this.readXlsxFile(fileName);
        // }

        for (const contactsChunk of chunks) {
            await this.addContactsToGroup(contactsChunk, groupId);
        }
    }


    async updateGroup(body: any) {
        let { groupId, name } = body;
        try {
            const group: any = await this.updateGroupName(groupId, name);
            return group;
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async createGroup(name) {
        const request = {
            url: `/v3/marketing/lists`,
            method: 'POST',
            body: { name },
        };
        try {
            const [response] = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async updateGroupName(groupId, name) {
        const request = {
            url: `/v3/marketing/lists/${groupId}`,
            method: 'PATCH',
            body: { name },
        };
        try {
            const [response] = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }
    async getGroup(queryParam: any) {
        const queryParams = { page_size: 50, page_token: queryParam.nextPageToken || '', name: queryParam.name };
        const request = {
            url: `/v3/marketing/lists`,
            method: 'GET',
            qs: queryParams,
        }; try {
            const [response]: any = await sgClient.request(request as any);
            const nextUrl = response.body._metadata?.next;

            const nextPageToken = nextUrl?.match(/page_token=([^&]+)/)?.[1];

            return { data: response.body, nextPageToken: nextPageToken ?? '' };
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async deleteGroup(param: any, queryParam) {
        const request = {
            url: `/v3/marketing/lists/${param.id}?delete_contacts=${queryParam.delete_contacts}`,
            method: 'DELETE',
        };
        console.log(request);
        try {
            const [response] = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            console.log(err);
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async addContactsToGroup(contacts, groupId) {
        const request = {
            url: `/v3/marketing/contacts`,
            method: 'PUT',
            body: {
                list_ids: [groupId],
                contacts: contacts
            },
        };
        try {
            const [response] = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            console.log(err);
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async getContacts(queryParam: any) {
        const queryParams = {
            page_size: 10,
            page_token: queryParam.nextPageToken || '',
        };
        const request = {
            url: `/v3/marketing/contacts`,
            method: 'GET',
            qs: queryParams,
        };
        try {
            const [response] = await sgClient.request(request as any);
            console.log(response.body);
            return response.body;
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async searchContacts(queryParam: any) {
        const data = {
            query: `(email LIKE '${queryParam.search}%' OR first_name LIKE '${queryParam.search}%') AND CONTAINS(list_ids, '${queryParam.groupId}')`,
        };
        const request = {
            url: `/v3/marketing/contacts/search`,
            method: 'POST',
            body: data,
        }; try {
            const [response] = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async deleteContacts(body: any) {
        const request = {
            url: `/v3/marketing/lists/${body.groupId}/contacts?contact_ids=${body.contactIds.join(',')}`,
            method: 'DELETE'
        };
        console.log(request);
        try {
            const [response] = await sgClient.request(request as any);
            return response.body;
        } catch (err) {
            console.log(err);
            throw new HttpException(err.response.body.errors[0].message, err.code || 500);
        }
    }

    async parseCSVBuffer(fileName): Promise<any[]> {
        const fileBuffer: any = await this.commonService.getAWSFile(`files/user-excel/${fileName}`);
        if (!fileBuffer) {
            throw new HttpException(responseMessages.en.user.file_not_exists, HttpStatus.NOT_FOUND);
        }
        let results: any = await new Promise((resolve, reject) => {
            const results = [];

            // Convert buffer → readable stream
            const stream = Readable.from(fileBuffer);

            stream
                .pipe(csv())
                .on('data', (row) => results.push(row))
                .on('end', () => resolve(results))
                .on('error', (err) => reject(err));
        });

        if (results.length > 0) {
            const chunkSize = 50; //15000
            const chunks = [];
            for (let i = 0; i < results.length; i += chunkSize) {
                chunks.push(results.slice(i, i + chunkSize));
            }
            return chunks;
        }
        return [];
    }

    async readXlsxFile(fileName: string) {
        const fileBuffer: any = await this.commonService.getAWSFile(`files/user-excel/${fileName}`);

        if (!fileBuffer) {
            throw new HttpException(responseMessages.en.user.file_not_exists, HttpStatus.NOT_FOUND);
        }

        const workbook = new ExcelJS.Workbook();
        // Load the buffer into the workbook
        await workbook.xlsx.load(fileBuffer);

        const worksheet = workbook.getWorksheet(1);
        const sheetArray = [];
        const headers = [];

        worksheet.getRow(1).eachCell((cell, colNumber) => {
            headers[colNumber] = cell.value || '';
        });

        // Loop through each row after the header
        worksheet.eachRow((row, rowNumber) => {
            if (rowNumber === 1) return; // Skip header row
            const rowData = {};
            headers.forEach((header, colNumber) => {
                const cell = row.getCell(colNumber);
                if (header === 'EMAIL' && cell.hyperlink) {
                    rowData[header] = cell.text;
                } else {
                    rowData[header] = cell.value !== undefined && cell.value !== null ? cell.value : '';
                }
            });
            sheetArray.push(rowData);
        });

        if (sheetArray.length > 0) {
            const chunkSize = 10;
            const chunks = [];
            for (let i = 0; i < sheetArray.length; i += chunkSize) {
                chunks.push(sheetArray.slice(i, i + chunkSize));
            }
            return chunks;
        }
        return [];
    }

}
