import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { responseMessages } from '../../messages/response-messages';
import { FileManagers } from '../../entities/file-managers.entity';
import { Users } from 'src/entities/users.entity';
import { Campaign } from 'src/entities/campaign.entity';
import { CampaignPayment } from 'src/entities/campaign_payment.entity';
import { SubscriptionHistory } from 'src/entities/subscription-history.entity';
import { Categories } from 'src/entities/categories.entity';
import { CampaignPaymentHistory } from 'src/entities/campaign_payment_history.entity';
const moment = require('moment');

@Injectable()
export class AdminRepository {
    constructor(
        @InjectRepository(FileManagers)
        private FileManagers: Repository<FileManagers>,
        @InjectRepository(Users)
        private Users: Repository<Users>,
        @InjectRepository(Campaign)
        private Campaign: Repository<Campaign>,
        @InjectRepository(CampaignPaymentHistory)
        private CampaignPaymentHistory: Repository<CampaignPaymentHistory>,
        @InjectRepository(SubscriptionHistory)
        private SubscriptionHistory: Repository<SubscriptionHistory>,
        @InjectRepository(Categories)
        private Categories: Repository<Categories>,
    ) { }

    async createFileManagerwithObject(request: any) {
        const result = await this.FileManagers.insert(request);
        if (result.raw.affected == 0) { return }

        const resultObject = await this.FileManagers.findOne({ where: { id: result.identifiers[0].id } });

        return resultObject;
    }

    async getDashboardCount(params: any) {

        const currentYear = new Date().getFullYear();

        const [users, campaignCount, campaignPayments, subscriptionPayments, categoryCount] = await Promise.all([

            this.Users.createQueryBuilder('user').select([
                `COUNT(CASE WHEN user.role = 'brand' THEN 1 END) AS totalBrands`,
                `COUNT(CASE WHEN user.role = 'influencer' THEN 1 END) AS totalInfluencer`,
                `COUNT(CASE WHEN user.role = 'influencer' AND user.is_verify_otp = true THEN 1 END) AS totalRegisteredInfluencer`,
            ]).getRawOne(),

            this.Campaign.count(),

            this.CampaignPaymentHistory.createQueryBuilder('campaignPayment')
                .select([
                    `SUM(final_amount_usd) AS campaignAmount`,
                    `SUM(CASE WHEN EXTRACT(YEAR FROM campaignPayment.created_at) = :year THEN campaignPayment.final_amount_usd ELSE 0 END) AS campaignYearAmount`
                ])
                .where("campaignPayment.payment_status = 'credited'")
                .setParameter('year', currentYear)
                .getRawOne(),

            this.SubscriptionHistory.createQueryBuilder('subscriptionHistory')
                .select([
                    `SUM(subscriptionHistory.final_amount) AS subscriptionAmount`,
                    `SUM(CASE WHEN EXTRACT(YEAR FROM subscriptionHistory.created_at) = :year THEN subscriptionHistory.final_amount ELSE 0 END) AS subscriptionYearAmount`
                ])
                .where("subscriptionHistory.status IN ('active', 'canceled')")
                .setParameter('year', currentYear)
                .getRawOne(),

            this.Categories.count()
        ]);

        // Calculate total earnings
        const totalEarnings = Number(campaignPayments?.campaignamount || 0) + Number(subscriptionPayments?.subscriptionamount || 0);
        const totalEarningsYear = Number(campaignPayments?.campaignyearamount || 0) + Number(subscriptionPayments?.subscriptionyearamount || 0);

        return {
            totalBrands: users.totalbrands,
            totalInfluencer: users.totalinfluencer,
            totalRegisteredInfluencer: users.totalregisteredinfluencer,
            campaignCount,
            totalEarnings,
            totalEarningsYear,
            categoryCount
        };
    }

    async getRevenueLineChart(params: any) {
        let response;
        switch (params.type) {
            case 'yearly':
                response = await this.getYearlyRevenueLineChart(params);
                break;
            case 'monthly':
                response = await this.getMonthlyRevenueLineChart(params);
                break;
            default:
                response = await this.getWeeklyRevenueLineChart(params);
                break;
        }
        return response;
    }

    async getYearlyRevenueLineChart(params: any) {
        const months = await this.getMonths(params.period);
        const revenueArr = [];
        for (const month of months) {
            const startDate = month.startDate;
            const endDate = month.endDate;
            const [campaignAmount, subscriptionAmount] = await this.commonQuery(startDate, endDate);
            revenueArr.push({ label: month.month, campaignAmount, subscriptionAmount });
        }
        return revenueArr;
    }

    async getMonthlyRevenueLineChart(params: any) {
        const days = await this.getNDays(params.period);
        const revenueArr = [];
        for (const day of days) {
            const startDate = day.startTime;
            const endDate = day.endTime;
            const [campaignAmount, subscriptionAmount] = await this.commonQuery(startDate, endDate);
            revenueArr.push({ label: day.date, campaignAmount, subscriptionAmount });
        }
        return revenueArr;
    }

    async getWeeklyRevenueLineChart(params: any) {
        const days = await this.getWeekDays();
        const revenueArr = [];
        for (const day of days) {
            const startDate = day.startDatetime;
            const endDate = day.endDatetime;
            const [campaignAmount, subscriptionAmount] = await this.commonQuery(startDate, endDate);
            revenueArr.push({ label: day.dayName, campaignAmount, subscriptionAmount });
        }
        return revenueArr;
    }



    async commonQuery(startDate: string, endDate: string) {
        const campaignPayment = await this.CampaignPaymentHistory.createQueryBuilder('campaignPayment')
            .select([
                `SUM(final_amount_usd) AS campaignAmount`
            ])
            .where("campaignPayment.payment_status = 'credited'")
            .where("campaignPayment.created_at >= :startDate AND campaignPayment.created_at <= :endDate", { startDate, endDate }) // Replace with the desired year
            .getRawOne();

        const campaignAmount = campaignPayment?.campaignamount || "0";

        const subscriptionPayment = await this.SubscriptionHistory.createQueryBuilder('subscriptionHistory')
            .select([
                `SUM(final_amount) AS subscriptionAmount`
            ])
            .where("subscriptionHistory.status IN ('active', 'canceled')")
            .where("subscriptionHistory.created_at >= :startDate AND subscriptionHistory.created_at <= :endDate", { startDate, endDate }) // Replace with the desired year
            .getRawOne();

        const subscriptionAmount = subscriptionPayment?.subscriptionamount || "0"
        return [campaignAmount, subscriptionAmount];
    }

    async getMonths(selectedYear: number) {
        const months = [];

        for (let month = 1; month <= 12; month++) {
            const startDate = moment(`${selectedYear}-${month}-01`, 'YYYY-MM-DD').startOf('month').format('YYYY-MM-DD');
            const endDate = moment(`${selectedYear}-${month}-01`, 'YYYY-MM-DD').endOf('month').format('YYYY-MM-DD');

            months.push({
                month: moment(`${selectedYear}-${month}-01`, 'YYYY-MM-DD').format('MMM-YYYY'), // Example: 'Jan-2024'
                startDate,
                endDate
            });
        }

        return months; // Reverse to maintain chronological order
    }

    async getNDays(selectedDate) {

        const [month, year] = selectedDate.split('-').map(Number);
        //const year = new Date().getFullYear(); // You can modify this to accept a year if needed

        const startOfMonth = moment(`${year}-${month}-01`);
        const endOfMonth = moment(startOfMonth).endOf('month');

        const dateList = [];

        for (let date = startOfMonth; date.isSameOrBefore(endOfMonth); date.add(1, 'day')) {
            dateList.push({
                date: date.format('YYYY-MM-DD'),
                startTime: date.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
                endTime: date.endOf('day').format('YYYY-MM-DD HH:mm:ss'),
            });
        }
        return dateList;

    }

    async getWeekDays() {
        const daysArray = [];
        let currentDate = moment().startOf('isoWeek'); // Start from Monday of the current week

        for (let i = 0; i < 7; i++) {
            const startDatetime = currentDate.clone().startOf('day').format('YYYY-MM-DD HH:mm:ss');
            const endDatetime = currentDate.clone().endOf('day').format('YYYY-MM-DD HH:mm:ss');

            daysArray.push({
                day: currentDate.format('YYYY-MM-DD'), // Date reference
                dayName: currentDate.format('dddd'),  // Day name
                startDatetime,
                endDatetime
            });

            // Move to the next day
            currentDate = currentDate.add(1, 'days');
        }

        return daysArray;
    }

}
