import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { UsersService } from '../users/users.service';
import { user_role } from '@prisma/client';
import { startOfDay, endOfDay, startOfMonth, endOfMonth, eachMonthOfInterval, format } from 'date-fns';

@Injectable()
export class ReportsService {
    constructor(
        private readonly prisma: PrismaService,
        private readonly usersService: UsersService
    ) { }

    async getSummaryData(filters: any, user: any) {
        const { startDate, endDate, targetUserId } = filters;

        // 1. Determine Scope
        let allowedUserIds: string[] = [user.id];

        if (user.role === user_role.ADMIN) {
            // Admin can see anyone or target a specific user
            if (targetUserId) {
                allowedUserIds = [targetUserId];
            } else {
                allowedUserIds = []; // Empty = All in our logic below
            }
        } else if ([user_role.GENERAL_MANAGER, user_role.MANAGER, user_role.OFFICER].includes(user.role)) {
            const subordinates = await this.usersService.getSubordinateIds(user.id);
            const managedIds = [user.id, ...subordinates];

            if (targetUserId) {
                // Check if target is a subordinate
                if (managedIds.includes(targetUserId)) {
                    allowedUserIds = [targetUserId];
                } else {
                    allowedUserIds = [user.id]; // Fallback to self
                }
            } else {
                allowedUserIds = managedIds;
            }
        } else {
            // Telesales Executive only sees self
            allowedUserIds = [user.id];
        }

        const dateRange = {
            gte: startDate ? new Date(startDate) : startOfMonth(new Date()),
            lte: endDate ? endOfDay(new Date(endDate)) : endOfMonth(new Date()),
        };

        const userFilter = allowedUserIds.length > 0 ? { userId: { in: allowedUserIds } } : {};
        const leadSharingFilter = allowedUserIds.length > 0
            ? { OR: [{ assignedTo: { in: allowedUserIds } }, { creatorId: { in: allowedUserIds } }] }
            : {};

        // 2. Fetch Aggregations
        const clientFilter = allowedUserIds.length > 0
            ? { assignedTo: { in: allowedUserIds } }
            : {};

        const [
            enquiries,
            opportunities,
            expenses,
            conversions
        ] = await Promise.all([
            // Enquiries breakdown
            this.prisma.enquiry.findMany({
                where: { ...userFilter, createdAt: dateRange },
                select: { id: true, status: true, createdAt: true }
            }),

            // Opportunity breakdown
            this.prisma.opportunity.findMany({
                where: { ...leadSharingFilter, updatedAt: dateRange },
                select: { id: true, stage: true, value: true, updatedAt: true, assignedTo: true, creatorId: true, isDemoDone: true }
            }),

            // Expense breakdown
            this.prisma.expense.findMany({
                where: { ...userFilter, date: dateRange },
                select: { id: true, amount: true, status: true }
            }),

            // Conversion data (already filtered by assignedTo)
            this.prisma.client.count({
                where: {
                    ...clientFilter,
                    status: { in: ['SALES', 'CLOSED'] },
                    updatedAt: dateRange
                }
            })
        ]);

        // 3. Process Trends (Last 6 months)
        const sixMonthsAgo = startOfMonth(new Date());
        sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 5);

        const months = eachMonthOfInterval({
            start: sixMonthsAgo,
            end: new Date(),
        });

        const salesTrend = await Promise.all(months.map(async (date) => {
            const monthStart = startOfMonth(date);
            const monthEnd = endOfMonth(date);

            const monthSales = await this.prisma.opportunity.aggregate({
                where: {
                    ...leadSharingFilter,
                    stage: 'SALES',
                    updatedAt: { gte: monthStart, lte: monthEnd }
                },
                _sum: { value: true }
            });

            return {
                month: format(date, 'MMM yy'),
                revenue: monthSales._sum?.value || 0
            };
        }));

        // 4. Team Performance (Only for Admin/Manager)
        let teamPerformance: any[] = [];
        if (user.role !== user_role.TELESALES_EXECUTIVE) {
            const usersToTrack = allowedUserIds.length > 0
                ? await this.prisma.user.findMany({ where: { id: { in: allowedUserIds } } })
                : await this.prisma.user.findMany({ take: 10 });

            teamPerformance = await Promise.all(usersToTrack.map(async (u) => {
                const [userSales, userEnq] = await Promise.all([
                    this.prisma.opportunity.aggregate({
                        where: { assignedTo: u.id, stage: 'SALES', updatedAt: dateRange },
                        _sum: { value: true }
                    }),
                    this.prisma.enquiry.count({
                        where: { userId: u.id, createdAt: dateRange }
                    })
                ]);

                return {
                    name: u.name,
                    revenue: userSales._sum?.value || 0,
                    enquiries: userEnq
                };
            }));
        }

        // 3. Process Summary with Revenue Split Logic
        const contributionRevenue = opportunities
            .filter(o => o.stage === 'SALES')
            .reduce((total, o) => {
                let share = 0;
                const isCloser = allowedUserIds.includes(o.assignedTo);
                const isCreator = o.creatorId && allowedUserIds.includes(o.creatorId);

                if (isCloser && isCreator) share = o.value; // Owns both
                else if (isCloser || isCreator) share = o.value * 0.5; // Shared

                return total + share;
            }, 0);

        return {
            summary: {
                totalEnquiries: enquiries.length,
                totalRevenue: opportunities.filter(o => o.stage === 'SALES').reduce((s, o) => s + o.value, 0),
                contributionRevenue,
                openPipeline: opportunities.filter(o => o.stage !== 'SALES').reduce((s, o) => s + o.value, 0),
                totalExpenses: expenses.reduce((s, e) => s + e.amount, 0),
                conversionCount: conversions
            },
            trends: {
                salesTrend
            },
            distribution: {
                stages: [
                    { name: 'Lead', count: opportunities.filter(o => o.stage === 'LEAD').length },
                    { name: 'Qualified', count: opportunities.filter(o => o.stage === 'QUALIFIED').length },
                    { name: 'Potential', count: opportunities.filter(o => o.stage === 'POTENTIAL').length },
                    { name: 'Demo Done', count: opportunities.filter(o => o.isDemoDone).length },
                    { name: 'SALES', count: opportunities.filter(o => o.stage === 'SALES').length },
                ],
                expenses: [
                    { name: 'Approved', amount: expenses.filter(e => e.status === 'APPROVED').reduce((s, e) => s + e.amount, 0) },
                    { name: 'Pending', amount: expenses.filter(e => e.status === 'PENDING').reduce((s, e) => s + e.amount, 0) },
                ]
            },
            teamPerformance: teamPerformance.sort((a, b) => b.revenue - a.revenue)
        };
    }
}
