/**
 * Shared Services - Reusable business logic for both super-admin and zone-admin
 * This prevents code duplication across admin types
 */

const mongoose = require('mongoose');
const Vendor = require('../models/vendor.model');
const Driver = require('../models/driver.model');
const Vehicle = require('../models/vehicle.model');
const Booking = require('../models/booking.model');
const Zone = require('../models/zone.model');
const VehicleModel = require('../models/vehicle-model.model');
const VehicleCategory = require('../models/vehicle-category.model');

// ==========================================
// ZONE HELPER
// ==========================================
exports.getAdminZone = async (userId) => {
    return Zone.findOne({ zoneAdmin: userId });
};

// ==========================================
// VENDOR SERVICES
// ==========================================
exports.getVendorsWithFilters = async (filters = {}, pagination = {}) => {
    const { zoneId, status, search, isDeleted = false } = filters;
    const { page = 1, limit = 10 } = pagination;
    const skip = (page - 1) * limit;

    const query = { isDeleted };
    if (zoneId) query.operationalZone = zoneId;
    if (status && status !== 'all') query.status = status;
    if (search) {
        query.$or = [
            { vendorName: { $regex: search, $options: 'i' } },
            { email: { $regex: search, $options: 'i' } },
            { vendorId: { $regex: search, $options: 'i' } }
        ];
    }

    const [list, total] = await Promise.all([
        Vendor.find(query)
            .populate('operationalZone', 'zoneName')
            .select('vendorId vendorName displayName email phone status createdAt documents')
            .skip(skip).limit(limit).sort({ createdAt: -1 }),
        Vendor.countDocuments(query)
    ]);

    return { list, total, pages: Math.ceil(total / limit), page };
};

exports.getVendorStats = async (zoneId = null) => {
    const match = { isDeleted: false };
    if (zoneId) match.operationalZone = new mongoose.Types.ObjectId(zoneId);

    const stats = await Vendor.aggregate([
        { $match: match },
        { $group: { _id: '$status', count: { $sum: 1 } } }
    ]);

    const result = { total: 0, active: 0, pending: 0, suspended: 0, rejected: 0 };
    stats.forEach(s => {
        result.total += s.count;
        if (s._id === 'Active') result.active = s.count;
        if (s._id === 'Pending') result.pending = s.count;
        if (s._id === 'Suspended') result.suspended = s.count;
        if (s._id === 'Rejected') result.rejected = s.count;
    });
    return result;
};

exports.getVendorById = async (vendorId, zoneId = null) => {
    const query = { _id: vendorId, isDeleted: false };
    if (zoneId) query.operationalZone = zoneId;

    return Vendor.findOne(query).populate('operationalZone', 'zoneName zoneAddress');
};

exports.getVendorWithStats = async (vendorId, zoneId = null) => {
    const vendor = await exports.getVendorById(vendorId, zoneId);
    if (!vendor) return null;

    const [orderStats, driverCount, vehicleCount] = await Promise.all([
        Booking.aggregate([
            { $match: { vendor: new mongoose.Types.ObjectId(vendorId) } },
            { $group: { _id: null, totalOrders: { $sum: 1 }, totalSales: { $sum: '$fare.total' } } }
        ]),
        Driver.countDocuments({ vendor: vendorId }),
        Vehicle.countDocuments({ vendor: vendorId })
    ]);

    const stats = orderStats[0] || { totalOrders: 0, totalSales: 0 };

    return {
        ...vendor.toObject(),
        stats: {
            totalOrders: stats.totalOrders,
            totalSales: Math.round(stats.totalSales || 0),
            totalCommission: Math.round((stats.totalSales || 0) * 0.1),
            totalDrivers: driverCount,
            totalVehicles: vehicleCount
        }
    };
};

exports.getTopVendors = async (zoneId = null, limit = 5) => {
    const match = { vendor: { $ne: null }, status: 'completed' };
    if (zoneId) match.zone = new mongoose.Types.ObjectId(zoneId);

    return Booking.aggregate([
        { $match: match },
        { $group: { _id: '$vendor', totalOrders: { $sum: 1 }, revenue: { $sum: '$fare.total' } } },
        { $sort: { totalOrders: -1 } },
        { $limit: limit },
        { $lookup: { from: 'vendors', localField: '_id', foreignField: '_id', as: 'vendor' } },
        { $unwind: '$vendor' },
        { $project: { _id: 1, vendorName: '$vendor.vendorName', totalOrders: 1, revenue: { $round: ['$revenue', 0] } } }
    ]);
};

// ==========================================
// DRIVER SERVICES
// ==========================================
exports.getDriversWithFilters = async (filters = {}, pagination = {}) => {
    const { zoneId, vendorId, status, search } = filters;
    const { page = 1, limit = 10 } = pagination;
    const skip = (page - 1) * limit;

    const query = {};
    if (zoneId) query.zone = zoneId;
    if (vendorId) query.vendor = vendorId;
    if (status && status !== 'all') query.status = status;
    if (search) {
        query.$or = [
            { fullName: { $regex: search, $options: 'i' } },
            { email: { $regex: search, $options: 'i' } },
            { phone: { $regex: search, $options: 'i' } }
        ];
    }

    const [list, total] = await Promise.all([
        Driver.find(query)
            .populate('zone', 'zoneName')
            .populate('vendor', 'vendorName')
            .populate('vehicle', 'vehicleName registrationNumber')
            .select('fullName email phone status rating totalTrips createdAt documents')
            .skip(skip).limit(limit).sort({ createdAt: -1 }),
        Driver.countDocuments(query)
    ]);

    return { list, total, pages: Math.ceil(total / limit), page };
};

exports.getDriverStats = async (zoneId = null) => {
    const match = {};
    if (zoneId) match.zone = new mongoose.Types.ObjectId(zoneId);

    const stats = await Driver.aggregate([
        { $match: match },
        { $group: { _id: '$status', count: { $sum: 1 } } }
    ]);

    const result = { total: 0, active: 0, pendingVerification: 0, suspended: 0, onTrip: 0, offDuty: 0 };
    stats.forEach(s => {
        result.total += s.count;
        if (s._id === 'active') result.active = s.count;
        if (s._id === 'pendingvarification') result.pendingVerification = s.count;
        if (s._id === 'suspended') result.suspended = s.count;
        if (s._id === 'ontrip') result.onTrip = s.count;
        if (s._id === 'inactive') result.offDuty = s.count;
    });
    return result;
};

exports.getDriverById = async (driverId, zoneId = null) => {
    const query = { _id: driverId };
    if (zoneId) query.zone = zoneId;

    return Driver.findOne(query)
        .populate('zone', 'zoneName')
        .populate('vendor', 'vendorName')
        .populate('vehicle', 'vehicleName registrationNumber');
};

exports.getDriverWithStats = async (driverId, zoneId = null) => {
    const driver = await exports.getDriverById(driverId, zoneId);
    if (!driver) return null;

    const [orderStats] = await Promise.all([
        Booking.aggregate([
            { $match: { driver: new mongoose.Types.ObjectId(driverId) } },
            { $group: { _id: null, totalTrips: { $sum: 1 }, totalEarnings: { $sum: '$fare.total' } } }
        ])
    ]);

    const stats = orderStats[0] || { totalTrips: 0, totalEarnings: 0 };

    return {
        ...driver.toObject(),
        stats: {
            totalTrips: stats.totalTrips,
            totalEarnings: Math.round(stats.totalEarnings || 0),
            walletBalance: 0, // Placeholder
            rating: driver.rating || 0
        }
    };
};

exports.getTopDrivers = async (zoneId = null, limit = 5) => {
    const match = { driver: { $ne: null }, status: 'completed' };
    if (zoneId) match.zone = new mongoose.Types.ObjectId(zoneId);

    return Booking.aggregate([
        { $match: match },
        { $group: { _id: '$driver', totalTrips: { $sum: 1 }, earnings: { $sum: '$fare.total' } } },
        { $sort: { totalTrips: -1 } },
        { $limit: limit },
        { $lookup: { from: 'drivers', localField: '_id', foreignField: '_id', as: 'driver' } },
        { $unwind: '$driver' },
        { $project: { _id: 1, fullName: '$driver.fullName', totalTrips: 1, earnings: { $round: ['$earnings', 0] }, rating: '$driver.rating' } }
    ]);
};

exports.getPendingDrivers = async (zoneId = null, limit = 5) => {
    const query = { status: 'pendingvarification' };
    if (zoneId) query.zone = zoneId;

    return Driver.find(query)
        .populate('zone', 'zoneName')
        .populate('vendor', 'vendorName')
        .select('fullName email phone createdAt documents')
        .sort({ createdAt: -1 })
        .limit(limit);
};

// ==========================================
// VEHICLE SERVICES
// ==========================================
exports.getVehiclesWithFilters = async (filters = {}, pagination = {}) => {
    const { zoneId, vendorId, status, search, category } = filters;
    const { page = 1, limit = 10 } = pagination;
    const skip = (page - 1) * limit;

    const query = {};
    if (zoneId) query.zone = zoneId;
    if (vendorId) query.vendor = vendorId;
    if (status && status !== 'all') query.status = status;

    if (search) {
        const searchRegex = new RegExp(search, 'i');
        const models = await VehicleModel.find({ modelName: searchRegex }).select('_id');
        const modelIds = models.map(m => m._id);

        query.$or = [
            { vehicleName: searchRegex },
            { registrationNumber: searchRegex },
            { model: { $in: modelIds } }
        ];
    }

    if (category && category !== 'all') {
        let categoryId = category;
        if (!mongoose.Types.ObjectId.isValid(category)) {
            const cat = await VehicleCategory.findOne({ categoryName: { $regex: category, $options: 'i' } });
            if (cat) categoryId = cat._id;
            else return { list: [], total: 0, pages: 0, page };
        }
        const models = await VehicleModel.find({ category: categoryId }).select('_id');
        query.model = { $in: models.map(m => m._id) };
    }

    const [list, total] = await Promise.all([
        Vehicle.find(query)
            .populate('vendor', 'vendorName')
            .populate('zone', 'zoneName')
            .populate({
                path: 'model',
                populate: [
                    { path: 'brandName', select: 'brandName logo' },
                    { path: 'category', select: 'categoryName' },
                    { path: 'group', select: 'groupName' }
                ]
            })
            .sort({ createdAt: -1 })
            .skip(skip).limit(limit),
        Vehicle.countDocuments(query)
    ]);

    return { list, total, pages: Math.ceil(total / limit), page };
};

exports.getVehicleStats = async (zoneId = null) => {
    const match = {};
    if (zoneId) match.zone = new mongoose.Types.ObjectId(zoneId);

    const stats = await Vehicle.aggregate([
        { $match: match },
        { $group: { _id: '$status', count: { $sum: 1 } } }
    ]);

    const result = { total: 0, active: 0, inactive: 0, onTrip: 0, pending: 0 };
    stats.forEach(s => {
        result.total += s.count;
        if (s._id === 'active') result.active = s.count;
        if (s._id === 'inactive') result.inactive = s.count;
        if (s._id === 'ontrip') result.onTrip = s.count;
        if (s._id === 'pending') result.pending = s.count;
    });
    return result;
};

exports.getPendingVehicles = async (zoneId = null, limit = 5) => {
    const query = { status: 'pending' };
    if (zoneId) query.zone = zoneId;

    return Vehicle.find(query)
        .populate('vendor', 'vendorName')
        .populate('zone', 'zoneName')
        .populate({
            path: 'model',
            select: 'brandName modelName category group',
            populate: [
                { path: 'brandName', select: 'brandName' },
                { path: 'category', select: 'categoryName' },
                { path: 'group', select: 'groupName' }
            ]
        })
        .select('registrationNumber status createdAt')
        .sort({ createdAt: -1 })
        .limit(limit);
};

exports.getVehicleById = async (vehicleId, zoneId = null) => {
    const query = { _id: vehicleId };
    if (zoneId) query.zone = zoneId;

    return Vehicle.findOne(query)
        .populate('vendor', 'vendorName')
        .populate('zone', 'zoneName')
        .populate({
            path: 'model',
            populate: [
                { path: 'brandName', select: 'brandName logo' },
                { path: 'category', select: 'categoryName' },
                { path: 'group', select: 'groupName' }
            ]
        });
};

// ==========================================
// ORDER SERVICES
// ==========================================
exports.getOrdersWithFilters = async (filters = {}, pagination = {}) => {
    const { zoneId, vendorId, driverId, status } = filters;
    const { page = 1, limit = 10 } = pagination;
    const skip = (page - 1) * limit;

    const query = {};
    if (zoneId) query.zone = zoneId;
    if (vendorId) query.vendor = vendorId;
    if (driverId) query.driver = driverId;
    if (status && status !== 'all') query.status = status;

    const [list, total] = await Promise.all([
        Booking.find(query)
            .populate('customer', 'fullName phone')
            .populate('driver', 'fullName phone')
            .populate('vendor', 'vendorName')
            .select('orderId status pickupLocation dropLocation fare tripType createdAt')
            .skip(skip).limit(limit).sort({ createdAt: -1 }),
        Booking.countDocuments(query)
    ]);

    return { list, total, pages: Math.ceil(total / limit), page };
};

exports.getOrderStats = async (zoneId = null) => {
    const match = {};
    if (zoneId) match.zone = new mongoose.Types.ObjectId(zoneId);

    const stats = await Booking.aggregate([
        { $match: match },
        {
            $group: {
                _id: null,
                total: { $sum: 1 },
                revenue: { $sum: '$fare.total' },
                completed: { $sum: { $cond: [{ $eq: ['$status', 'completed'] }, 1, 0] } },
                cancelled: { $sum: { $cond: [{ $eq: ['$status', 'cancelled'] }, 1, 0] } },
                active: { $sum: { $cond: [{ $in: ['$status', ['created', 'assigned', 'arrived', 'inProgress']] }, 1, 0] } }
            }
        }
    ]);

    const result = stats[0] || { total: 0, revenue: 0, completed: 0, cancelled: 0, active: 0 };
    result.revenue = Math.round(result.revenue || 0);
    return result;
};

exports.getOngoingOrders = async (zoneId = null, limit = 10) => {
    const query = { status: { $in: ['created', 'assigned', 'arrived', 'inProgress'] } };
    if (zoneId) query.zone = zoneId;

    return Booking.find(query)
        .populate('customer', 'fullName phone')
        .populate('driver', 'fullName phone')
        .select('orderId status pickupLocation dropLocation fare.total createdAt')
        .sort({ createdAt: -1 })
        .limit(limit);
};
