const bostaService = require('../utils/bostaService'); const ShippingPrice = require('../models/shippingPriceModel'); // Get all Cities (Governorates) merged with our local price data exports.getGovernorates = async (req, res) => { try { const bostaData = await bostaService.getBostaCities(); const governorates = bostaData.data || bostaData; // Fetch our local pricing data const localPrices = await ShippingPrice.find(); const priceMap = new Map(localPrices.map((p) => [p.bostaCityId, p])); // Merge price data into governorates list const mergedGovernorates = governorates.map((gov) => { const localData = priceMap.get(gov._id); return { ...gov, // Normalize names for frontend (Bosta uses name and nameAr strings) name: { ar: gov.nameAr || gov.name || (gov._id === 'Jrb6X6ucjiYgMP4T7' ? 'الإسكندرية' : ''), en: gov.name || (gov._id === 'Jrb6X6ucjiYgMP4T7' ? 'Alexandria' : ''), }, fees: localData ? localData.fees || 0 : 0, deliveryDays: localData ? localData.deliveryDays || 3 : 3, isActive: localData ? localData.isActive !== false : true, }; }); res.status(200).json({ status: 'success', results: mergedGovernorates.length, data: { governorates: mergedGovernorates, }, }); } catch (err) { res.status(500).json({ status: 'error', message: 'Failed to fetch governorates', error: err.message, }); } }; // Update or Create Shipping Fee for a City exports.updateShippingFee = async (req, res) => { try { const { bostaCityId, bostaZoneId, type = 'city', fees, deliveryDays, areaNameAr, areaNameEn, isActive, } = req.body; if (!bostaCityId) { return res.status(400).json({ status: 'fail', message: 'Bosta City ID is required', }); } // Search by both City and Zone ID to ensure uniqueness for zones // For better control, we'll explicitly pick which one to match if multiple exist // But usually there should be only one city document const shippingPrice = await ShippingPrice.findOneAndUpdate( { bostaCityId, bostaZoneId: bostaZoneId || null }, { fees, deliveryDays, areaNameAr, areaNameEn, type, isActive, }, { new: true, upsert: true, runValidators: true, setDefaultsOnInsert: true, }, ); res.status(200).json({ status: 'success', data: { shippingPrice, }, }); } catch (err) { res.status(500).json({ status: 'error', message: 'Failed to update shipping fee', error: err.message, }); } }; // Get Zones (Areas/Districts) for a City exports.getCities = async (req, res) => { try { const { id } = req.params; // governorate ID const data = await bostaService.getBostaZones(id); const zones = data.data || data; // Fetch local prices for these zones const localPrices = await ShippingPrice.find({ bostaCityId: id, type: 'zone', }); const priceMap = new Map(localPrices.map((p) => [p.bostaZoneId, p])); const mergedZones = zones.map((zone) => { const localData = priceMap.get(zone._id); return { ...zone, name: { ar: zone.nameAr || zone.name, en: zone.name, }, fees: localData ? localData.fees : 0, isActive: localData ? localData.isActive : true, }; }); res.status(200).json({ status: 'success', results: mergedZones.length, data: { cities: mergedZones, }, }); } catch (err) { res.status(500).json({ status: 'error', message: 'Failed to fetch cities', error: err.message, }); } }; // Get Districts for a City/Governorate exports.getDistricts = async (req, res) => { try { const { id } = req.params; // governorate ID const data = await bostaService.getBostaDistricts(id); const districts = data.data || data; const normalizedDistricts = districts.map((d) => ({ _id: d.districtId, zoneId: d.zoneId, name: { ar: d.districtOtherName || d.districtName, en: d.districtName, }, })); res.status(200).json({ status: 'success', results: normalizedDistricts.length, data: { districts: normalizedDistricts, }, }); } catch (err) { res.status(500).json({ status: 'error', message: 'Failed to fetch districts', error: err.message, }); } };