/**
 * Dashboard Service
 * Business logic for dashboard statistics and analytics
 * Supports both super-admin (all data) and zone-admin (zone-scoped data)
 */
const User = require('../models/user.model');
const Vendor = require('../models/vendor.model');
const Zone = require('../models/zone.model');
const Booking = require('../models/booking.model');
const Driver = require('../models/driver.model');
const Vehicle = require('../models/vehicle.model');
const { getLiveOrdersWithCounts } = require('./booking.service');
const mongoose = require('mongoose')
// ==========================================
// ZONE-SCOPED DASHBOARD (for zone-admin)
// ==========================================

/**
 * Get dashboard statistics scoped to a specific zone
 * @param {ObjectId} zoneId - Zone ID to filter by
 */
exports.getZoneDashboardStats = async (zoneId) => {
    const zoneFilter = { operationalZone: zoneId };
    const zoneBookingFilter = { zone: zoneId };

    const [
        totalVendors,
        totalDrivers,
        totalVehicles,
        bookingStats,
        revenueData
    ] = await Promise.all([
        Vendor.countDocuments({ ...zoneFilter, isDeleted: false }),
        Driver.countDocuments({ zone: zoneId }),
        Vehicle.countDocuments({ zone: zoneId }),
        Booking.aggregate([
            { $match: zoneBookingFilter },
            { $group: { _id: '$status', count: { $sum: 1 } } }
        ]),
        Booking.aggregate([
            { $match: { ...zoneBookingFilter, status: 'completed' } },
            { $group: { _id: null, totalRevenue: { $sum: '$fare.total' } } }
        ])
    ]);

    const rideStats = { total: 0, completed: 0, cancelled: 0, active: 0 };
    bookingStats.forEach(stat => {
        rideStats.total += stat.count;
        if (stat._id === 'completed') rideStats.completed = stat.count;
        else if (stat._id === 'cancelled') rideStats.cancelled = stat.count;
        else if (stat._id !== 'payment_pending') rideStats.active += stat.count;
    });

    return {
        totalVendors,
        totalDrivers,
        totalVehicles,
        totalRides: rideStats.total,
        completedRides: rideStats.completed,
        cancelledRides: rideStats.cancelled,
        activeRides: rideStats.active,
        totalRevenue: revenueData[0]?.totalRevenue || 0
    };
};

/**
 * Get top vendors for a specific zone
 * @param {ObjectId} zoneId - Zone ID to filter by
 * @param {Number} limit - Max vendors to return
 */
exports.getTopVendorsForZone = async (zoneId, limit = 10) => {
    // First get vendors in this zone
    const zoneVendorIds = await Vendor.find({ operationalZone: zoneId, isDeleted: false }).select('_id');
    const vendorIds = zoneVendorIds.map(v => v._id);

    return Booking.aggregate([
        { $match: { zone: zoneId, status: 'completed', vendor: { $in: vendorIds } } },
        { $group: { _id: '$vendor', totalBookings: { $sum: 1 }, revenue: { $sum: '$fare.total' } } },
        { $sort: { totalBookings: -1 } },
        { $limit: parseInt(limit) },
        { $lookup: { from: 'vendors', localField: 'vendor', foreignField: '_id', as: 'vendor' } },
        { $unwind: '$vendor' },
        { $project: { _id: 1, vendorName: '$vendor.vendorName', displayName: '$vendor.displayName', totalBookings: 1, revenue: { $round: ['$revenue', 2] } } }
    ]);
};

/**
 * Get top drivers for a specific zone (via vendor association)
 * @param {ObjectId} zoneId - Zone ID to filter by
 * @param {Number} limit - Max drivers to return
 */
exports.getTopDriversForZone = async (zoneId, limit = 10) => {
    return Booking.aggregate([
        { $match: { zone: zoneId, status: 'completed', driver: { $exists: true, $ne: null } } },
        { $group: { _id: '$driver', totalRides: { $sum: 1 }, revenue: { $sum: '$fare.total' } } },
        { $sort: { totalRides: -1 } },
        { $limit: parseInt(limit) },
        { $lookup: { from: 'drivers', localField: 'driver', foreignField: '_id', as: 'driver' } },
        { $unwind: '$driver' },
        { $project: { _id: 1, fullName: '$driver.fullName', phone: '$driver.phone', email: '$driver.email', totalRides: 1, revenue: { $round: ['$revenue', 2] } } }
    ]);
};

/**
 * Get live orders for a specific zone
 * @param {ObjectId} zoneId - Zone ID to filter by
 * @param {Number} limit - Max orders to return
 */
exports.getLiveOrdersForZone = async (zoneId, limit = 20) => {
    const activeStatuses = ['Created', 'Assigned', 'Arrived', 'InProgress'];

    const [liveOrders, statusCounts] = await Promise.all([
        Booking.find({ zone: zoneId, status: { $in: ['created', 'assigned', 'arrived', 'inProgress'] } })
            .populate('customer', 'fullName phone')
            .populate('driver', 'fullName phone')
            .populate('vendor', 'vendorName')
            .select('orderId status pickupLocation dropLocation fare.total tripType createdAt')
            .sort({ createdAt: -1 })
            .limit(parseInt(limit)),
        Booking.aggregate([
            { $match: { zone: zoneId, status: { $in: ['created', 'assigned', 'arrived', 'inProgress'] } } },
            { $group: { _id: '$status', count: { $sum: 1 } } }
        ])
    ]);

    const counts = { created: 0, assigned: 0, arrived: 0, inProgress: 0, total: 0 };
    statusCounts.forEach(stat => {
        const key = stat._id.charAt(0).toLowerCase() + stat._id.slice(1);
        if (counts.hasOwnProperty(key)) {
            counts[key] = stat.count;
        }
        counts.total += stat.count;
    });

    return { liveOrders, counts };
};

/**
 * Get full zone dashboard data in one call (for zone-admin)
 * @param {ObjectId} zoneId - Zone ID to filter by
 * @param {Number} topLimit - Limit for top lists
 */
exports.getZoneFullDashboard = async (zoneId, topLimit = 10) => {
    const [stats, topVendors, topDrivers, liveOrdersResult] = await Promise.all([
        exports.getZoneDashboardStats(zoneId),
        exports.getTopVendorsForZone(zoneId, topLimit),
        exports.getTopDriversForZone(zoneId, topLimit),
        exports.getLiveOrdersForZone(zoneId, 20)
    ]);

    return {
        stats,
        topVendors,
        topDrivers,
        liveOrders: liveOrdersResult.liveOrders,
        liveOrdersCounts: liveOrdersResult.counts
    };
};

// ==========================================
// SUPER ADMIN DASHBOARD (all zones)
// ==========================================

/**
 * Get unified dashboard statistics for super admin
 */
exports.getDashboardStats = async () => {
    const [
        totalUsers,
        totalVendors,
        totalZones,
        totalDrivers,
        totalVehicles,
        bookingStats,
        revenueData
    ] = await Promise.all([
        User.countDocuments({ role: 'user' }),
        Vendor.countDocuments({ isDeleted: false }),
        Zone.countDocuments({}), // TODO: Add isActive filter if required
        Driver.countDocuments(),
        Vehicle.countDocuments(),
        Booking.aggregate([
            { $group: { _id: '$status', count: { $sum: 1 } } }
        ]),
        Booking.aggregate([
            { $match: { status: 'completed' } },
            { $group: { _id: null, totalRevenue: { $sum: '$fare.total' } } }
        ])
    ]);

    const rideStats = { total: 0, completed: 0, cancelled: 0, created: 0, assigned: 0, inProgress: 0 };
    bookingStats.forEach(stat => {
        rideStats.total += stat.count;
        const key = stat._id?.toLowerCase() || 'created';
        if (key !== 'payment_pending' && rideStats.hasOwnProperty(key)) {
            rideStats[key] = stat.count;
        }
    });

    return {
        totalUsers,
        totalVendors,
        totalZones,
        totalDrivers,
        totalVehicles,
        totalRides: rideStats.total,
        completedRides: rideStats.completed,
        cancelledRides: rideStats.cancelled,
        activeRides: rideStats.created + rideStats.assigned + rideStats.inProgress,
        totalRevenue: revenueData[0]?.totalRevenue || 0
    };
};

/**
 * Get top vendors by completed bookings (super admin)
 * @param {Number} limit - Max vendors to return
 * @param {ObjectId} zoneId - Optional zone filter
 */
exports.getTopVendorsSuperAdmin = async (limit = 10, zoneId = null) => {
    const matchStage = { status: 'completed', vendor: { $exists: true, $ne: null } };
    if (zoneId) {
        matchStage.zone = new mongoose.Types.ObjectId(zoneId);
    }
    return Booking.aggregate([
        { $match: matchStage },
        { $group: { _id: '$vendor', totalBookings: { $sum: 1 }, revenue: { $sum: '$fare.total' } } },
        { $sort: { totalBookings: -1 } },
        { $limit: parseInt(limit) },
        { $lookup: { from: 'vendors', localField: '_id', foreignField: '_id', as: 'vendor' } },
        { $unwind: '$vendor' },
        { $project: { _id: 1, vendorName: '$vendor.vendorName', vendorEmail: '$vendor.email', vendorPhone: '$vendor.phone', totalBookings: 1, revenue: 1 } }
    ]);
};

/**
 * Get top users by booking count (super admin)
 */
exports.getTopUsersSuperAdmin = async (limit = 10) => {
    return Booking.aggregate([
        {
            $group: {
                _id: '$customer',
                completedBookings: { $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] } },
                totalSpent: { $sum: { $cond: [{ $eq: ['$status', 'completed'] }, '$fare.total', 0] } }
            }
        },
        { $sort: { completedBookings: -1 } },
        { $limit: parseInt(limit) },
        { $lookup: { from: 'users', localField: '_id', foreignField: '_id', as: 'user' } },
        { $unwind: '$user' },
        { $project: { _id: 1, fullName: '$user.fullName', email: '$user.email', phone: '$user.phone', completedBookings: 1, totalSpent: 1 } }
    ]);
};

/**
 * Get zone-wise sales breakdown
 */
exports.getZoneWiseSales = async (dateRange = {}) => {
    const { startDate, endDate } = dateRange;

    const matchStage = { status: 'completed' };
    if (startDate && endDate) {
        matchStage.createdAt = { $gte: new Date(startDate), $lte: new Date(endDate) };
    }

    const zoneSales = await Booking.aggregate([
        { $match: matchStage },
        { $group: { _id: '$zone', totalBookings: { $sum: 1 }, totalRevenue: { $sum: '$fare.total' }, avgFare: { $avg: '$fare.total' } } },
        { $sort: { totalRevenue: -1 } },
        { $lookup: { from: 'zones', localField: '_id', foreignField: '_id', as: 'zone' } },
        { $unwind: { path: '$zone', preserveNullAndEmptyArrays: true } },
        // Lookup zone admin details from the zone's zoneAdmin reference
        { $lookup: { from: 'zoneadmins', localField: 'zone.zoneAdmin', foreignField: '_id', as: 'zoneAdmin' } },
        { $unwind: { path: '$zoneAdmin', preserveNullAndEmptyArrays: true } },
        { $project: { _id: 1, zoneName: '$zone.zoneName', city: '$zone.zoneAddress.city', zoneAdminName: '$zoneAdmin.fullName', totalBookings: 1, totalRevenue: { $round: ['$totalRevenue', 2] }, avgFare: { $round: ['$avgFare', 2] } } }
    ]);

    const grandTotal = zoneSales.reduce((sum, zone) => sum + zone.totalRevenue, 0);

    return {
        zoneSales: zoneSales.map(zone => ({
            ...zone,
            percentage: grandTotal > 0 ? Math.round((zone.totalRevenue / grandTotal) * 100) : 0
        })),
        summary: { totalZones: zoneSales.length, grandTotal: Math.round(grandTotal * 100) / 100 }
    };
};

/**
 * Get live/active orders
 */
// exports.getLiveOrdersSuperAdmin = async (limit = 20) => {
//     const activeStatuses = ['Created', 'Assigned', 'Arrived', 'InProgress'];

//     const [liveOrders, statusCounts] = await Promise.all([
//         Booking.find({ status: { $in: activeStatuses } })
//             .populate('customer', 'fullName phone')
//             .populate('driver', 'fullName phone')
//             .populate('zone', 'zoneName')
//             .select('orderId status pickupLocation dropLocation fare.total tripType createdAt')
//             .sort({ createdAt: -1 })
//             .limit(parseInt(limit)),
//         Booking.aggregate([
//             { $match: { status: { $in: activeStatuses } } },
//             { $group: { _id: '$status', count: { $sum: 1 } } }
//         ])
//     ]);

//     const counts = { created: 0, assigned: 0, arrived: 0, inProgress: 0, total: 0 };
//     statusCounts.forEach(stat => {
//         const key = stat._id.charAt(0).toLowerCase() + stat._id.slice(1);
//         if (counts.hasOwnProperty(key)) counts[key] = stat.count;
//         counts.total += stat.count;
//     });

//     return { liveOrders, counts };
// };

/**
 * Get full dashboard data in one call 
 */
exports.getFullDashboardData = async (topLimit = 10) => {
    const [topUsers, liveOrdersResult] = await Promise.all([
        // exports.getDashboardStats(),
        // exports.getTopVendorsSuperAdmin(topLimit),
        exports.getTopUsersSuperAdmin(topLimit),
        // exports.getZoneWiseSales({}),
        getLiveOrdersWithCounts(20)
    ]);

    return {
        // stats,
        // topVendors,
        topUsers,
        // zoneSales: zoneSalesResult.zoneSales,
        liveOrders: liveOrdersResult.liveOrders
    };
};



/**
 * Get sales summary with daily, weekly, or monthly breakdown
 * @param {String} period - 'daily' | 'weekly' | 'monthly'
 * @param {ObjectId} zoneId - Optional zone filter for zone-admin
 */
exports.getSalesSummary = async (period = 'daily', zoneId = null) => {
    const now = new Date();
    let groupBy, dateRange, labelFormat;
    const dayNames = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];

    // Determine date range and grouping based on period
    if (period === 'daily') {
        // Current week (Sunday to Saturday)
        const dayOfWeek = now.getDay();
        const startOfWeek = new Date(now);
        startOfWeek.setDate(now.getDate() - dayOfWeek);
        startOfWeek.setHours(0, 0, 0, 0);

        const endOfWeek = new Date(startOfWeek);
        endOfWeek.setDate(startOfWeek.getDate() + 6);
        endOfWeek.setHours(23, 59, 59, 999);

        dateRange = { $gte: startOfWeek, $lte: endOfWeek };
        groupBy = { $dayOfWeek: '$createdAt' }; // 1=Sunday, 7=Saturday
        labelFormat = 'dayOfWeek';
    } else if (period === 'weekly') {
        // Last 7 weeks
        const startDate = new Date(now);
        startDate.setDate(now.getDate() - 49); // 7 weeks ago
        startDate.setHours(0, 0, 0, 0);

        dateRange = { $gte: startDate, $lte: now };
        groupBy = { $isoWeek: '$createdAt' };
        labelFormat = 'week';
    } else if (period === 'monthly') {
        // Last 12 months
        const startDate = new Date(now);
        startDate.setMonth(now.getMonth() - 11);
        startDate.setDate(1);
        startDate.setHours(0, 0, 0, 0);

        dateRange = { $gte: startDate, $lte: now };
        groupBy = { $month: '$createdAt' };
        labelFormat = 'month';
    } else {
        throw new Error('Invalid period. Use: daily, weekly, or monthly');
    }

    // Build match stage
    const matchStage = { createdAt: dateRange };
    if (zoneId) {
        matchStage.zone = zoneId;
    }

    // Aggregation pipeline
    const salesData = await Booking.aggregate([
        { $match: matchStage },
        {
            $group: {
                _id: {
                    period: groupBy,
                    year: { $year: '$createdAt' }
                },
                completedRevenue: {
                    $sum: { $cond: [{ $eq: ['$status', 'completed'] }, '$fare.total', 0] }
                },
                totalBookings: {
                    $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] }
                },
                pendingRevenue: {
                    $sum: { $cond: [{ $ne: ['$status', 'completed'] }, '$fare.total', 0] }
                },
                pendingBookings: {
                    $sum: { $cond: [{ $ne: ['$status', 'completed'] }, 1, 0] }
                }
            }
        },
        { $sort: { '_id.year': 1, '_id.period': 1 } }
    ]);

    // Format response based on period type
    const monthNames = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];

    let formattedData = [];

    if (labelFormat === 'dayOfWeek') {
        // Initialize all days with 0 values
        formattedData = dayNames.map((day, idx) => ({
            label: day,
            dayIndex: idx + 1, // MongoDB dayOfWeek: 1=Sunday
            completedRevenue: 0,
            totalBookings: 0,
            avgFare: 0,
            pendingRevenue: 0
        }));

        // Fill in actual data
        salesData.forEach(item => {
            const dayIdx = item._id.period - 1; // Convert to 0-indexed
            if (dayIdx >= 0 && dayIdx < 7) {
                formattedData[dayIdx].completedRevenue = Math.round(item.completedRevenue || 0);
                formattedData[dayIdx].totalBookings = item.totalBookings || 0;
                formattedData[dayIdx].avgFare = item.totalBookings > 0
                    ? Math.round(item.completedRevenue / item.totalBookings)
                    : 0;
                formattedData[dayIdx].pendingRevenue = Math.round(item.pendingRevenue || 0);
            }
        });
    } else if (labelFormat === 'week') {
        formattedData = salesData.map(item => ({
            label: `Week ${item._id.period}`,
            week: item._id.period,
            year: item._id.year,
            completedRevenue: Math.round(item.completedRevenue || 0),
            totalBookings: item.totalBookings || 0,
            avgFare: item.totalBookings > 0
                ? Math.round(item.completedRevenue / item.totalBookings)
                : 0,
            pendingRevenue: Math.round(item.pendingRevenue || 0)
        }));
    } else if (labelFormat === 'month') {
        // Initialize all 12 months
        formattedData = monthNames.map((month, idx) => ({
            label: month,
            monthIndex: idx + 1,
            completedRevenue: 0,
            totalBookings: 0,
            avgFare: 0,
            pendingRevenue: 0
        }));

        // Fill in actual data
        salesData.forEach(item => {
            const monthIdx = item._id.period - 1; // Convert to 0-indexed
            if (monthIdx >= 0 && monthIdx < 12) {
                formattedData[monthIdx].completedRevenue = Math.round(item.completedRevenue || 0);
                formattedData[monthIdx].totalBookings = item.totalBookings || 0;
                formattedData[monthIdx].avgFare = item.totalBookings > 0
                    ? Math.round(item.completedRevenue / item.totalBookings)
                    : 0;
                formattedData[monthIdx].pendingRevenue = Math.round(item.pendingRevenue || 0);
            }
        });
    }

    // Calculate summary totals
    const summary = {
        totalCompletedRevenue: formattedData.reduce((sum, d) => sum + d.completedRevenue, 0),
        totalPendingRevenue: formattedData.reduce((sum, d) => sum + d.pendingRevenue, 0),
        totalBookings: formattedData.reduce((sum, d) => sum + d.totalBookings, 0),
        avgFare: 0
    };
    summary.avgFare = summary.totalBookings > 0
        ? Math.round(summary.totalCompletedRevenue / summary.totalBookings)
        : 0;

    return {
        period,
        data: formattedData,
        summary
    };
};