"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TrackingService = exports.SUPPORTED_CARRIERS = void 0;
const database_1 = __importDefault(require("../config/database"));
exports.SUPPORTED_CARRIERS = {
    delhivery: {
        name: 'Delhivery Surface & Express',
        slug: 'delhivery',
        trackingUrlTemplate: 'https://www.delhivery.com/track/package/{trackingNumber}',
        supportPhone: '+91 124 6719500',
        supportEmail: 'customer.support@delhivery.com',
        averageDeliveryDays: '2-4 business days across India',
        logo: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=120&auto=format&fit=crop&q=80',
    },
    bluedart: {
        name: 'Blue Dart Express (DHL Network)',
        slug: 'bluedart',
        trackingUrlTemplate: 'https://www.bluedart.com/tracking/{trackingNumber}',
        supportPhone: '1860 233 1234',
        supportEmail: 'track@bluedart.com',
        averageDeliveryDays: '1-3 business days (Priority Air)',
        logo: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=120&auto=format&fit=crop&q=80',
    },
    indiapost: {
        name: 'India Post (Speed Post / Regd. Book Post)',
        slug: 'indiapost',
        trackingUrlTemplate: 'https://www.indiapost.gov.in/_layouts/15/dpt.cpt.stats/etrac/ek.aspx?ArticleId={trackingNumber}',
        supportPhone: '1800 266 6868',
        supportEmail: 'speedpost@indiapost.gov.in',
        averageDeliveryDays: '3-6 business days nationwide',
        logo: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=120&auto=format&fit=crop&q=80',
    },
    dhl: {
        name: 'DHL Express Worldwide (International)',
        slug: 'dhl',
        trackingUrlTemplate: 'https://www.dhl.com/in-en/home/tracking/tracking-express.html?submit=1&tracking-id={trackingNumber}',
        supportPhone: '1800 111 345 / 1800 200 1345',
        supportEmail: 'international.support@dhl.com',
        averageDeliveryDays: '3-7 business days global air cargo',
        logo: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=120&auto=format&fit=crop&q=80',
    },
    dtdc: {
        name: 'DTDC Courier & Cargo',
        slug: 'dtdc',
        trackingUrlTemplate: 'https://www.dtdc.in/tracking/shipment-tracking.asp?trkid={trackingNumber}',
        supportPhone: '+91 73057 70577',
        supportEmail: 'customersupport@dtdc.com',
        averageDeliveryDays: '2-5 business days',
        logo: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=120&auto=format&fit=crop&q=80',
    },
    fedex: {
        name: 'FedEx Express India',
        slug: 'fedex',
        trackingUrlTemplate: 'https://www.fedex.com/fedextrack/?trknbr={trackingNumber}',
        supportPhone: '1800 209 6161',
        supportEmail: 'india@fedex.com',
        averageDeliveryDays: '2-4 business days',
        logo: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=120&auto=format&fit=crop&q=80',
    },
};
class TrackingService {
    /**
     * Public Order & Shipment Tracker
     * Searches by trackingNumber (e.g. DELHIVERY-89210) OR orderNumber (e.g. IBW-98201)
     */
    static async trackPublic(query) {
        const cleanQuery = query.trim();
        // 1. Search directly in Shipments table by trackingNumber
        let shipment = await database_1.default.shipment.findFirst({
            where: {
                OR: [
                    { trackingNumber: { equals: cleanQuery } },
                    { order: { orderNumber: { equals: cleanQuery } } },
                    { orderId: { equals: cleanQuery } },
                ],
            },
            include: {
                events: {
                    orderBy: { timestamp: 'desc' },
                },
                order: {
                    include: {
                        shippingAddress: true,
                        items: {
                            include: {
                                book: {
                                    select: {
                                        id: true,
                                        title: true,
                                        slug: true,
                                        coverImage: true,
                                        binding: true,
                                    },
                                },
                                variant: {
                                    select: {
                                        id: true,
                                        title: true,
                                        format: true,
                                        sku: true,
                                    },
                                },
                            },
                        },
                    },
                },
            },
        });
        // 2. If no shipment record exists yet, check if order exists
        if (!shipment) {
            const order = await database_1.default.order.findFirst({
                where: {
                    OR: [
                        { orderNumber: { equals: cleanQuery } },
                        { id: { equals: cleanQuery } },
                    ],
                },
                include: {
                    shippingAddress: true,
                    items: {
                        include: {
                            book: {
                                select: {
                                    id: true,
                                    title: true,
                                    slug: true,
                                    coverImage: true,
                                    binding: true,
                                },
                            },
                            variant: {
                                select: {
                                    id: true,
                                    title: true,
                                    format: true,
                                    sku: true,
                                },
                            },
                        },
                    },
                },
            });
            if (!order) {
                throw new Error(`No shipment or order found matching “${cleanQuery}”. Please check your tracking number or Order ID.`);
            }
            // Synthesize order tracking representation for an order awaiting courier pickup
            const carrierInfo = exports.SUPPORTED_CARRIERS.delhivery;
            const orderDate = order.createdAt;
            const estimatedDelivery = new Date(orderDate.getTime() + 4 * 24 * 60 * 60 * 1000);
            return {
                orderNumber: order.orderNumber,
                trackingNumber: `IBW-TRK-${order.orderNumber.replace(/[^0-9]/g, '') || '001'}`,
                carrier: carrierInfo.name,
                carrierSlug: carrierInfo.slug,
                carrierTrackingUrl: carrierInfo.trackingUrlTemplate.replace('{trackingNumber}', order.orderNumber),
                carrierInfo,
                status: order.status === 'PROCESSING' ? 'PROCESSING' : order.status === 'CONFIRMED' ? 'CONFIRMED' : 'ORDER_PLACED',
                statusLabel: order.status === 'PROCESSING' ? 'Packed & Ready for Courier Dispatch' : 'Order Confirmed & Allocated',
                currentLocation: 'New Delhi Central Vedic Fulfillment Center',
                orderDate: order.createdAt,
                estimatedDelivery,
                destinationCity: order.shippingAddress.city,
                destinationState: order.shippingAddress.state,
                destinationPostalCode: order.shippingAddress.postalCode,
                destinationCountry: order.shippingAddress.country,
                maskedRecipient: `${order.shippingAddress.fullName.slice(0, 2)}**** ${order.shippingAddress.fullName.split(' ').slice(-1)[0] || ''}`,
                items: order.items.map((item) => ({
                    title: item.variant?.title || item.book.title,
                    format: item.variant?.format || item.book.binding || 'Book',
                    quantity: item.quantity,
                    coverImage: item.book.coverImage,
                })),
                timeline: [
                    {
                        status: 'ORDER_PLACED',
                        title: 'Order Confirmed & Payment Verified',
                        description: `Payment secured for Order ${order.orderNumber}. Order routed to fulfillment.`,
                        location: 'New Delhi E-Commerce Hub',
                        timestamp: order.createdAt,
                        source: 'SYSTEM',
                    },
                    ...(order.status === 'PROCESSING'
                        ? [
                            {
                                status: 'PROCESSING',
                                title: 'Archival Inspection & Protective Packaging',
                                description: 'Items inspected for print quality and packed with moisture-resistant protective layers.',
                                location: 'New Delhi Fulfillment Center',
                                timestamp: new Date(order.createdAt.getTime() + 2 * 60 * 60 * 1000),
                                source: 'SYSTEM',
                            },
                        ]
                        : []),
                ],
            };
        }
        // 3. Return full shipment data
        const carrierSlug = shipment.carrierSlug.toLowerCase();
        const carrierInfo = exports.SUPPORTED_CARRIERS[carrierSlug] || {
            name: shipment.carrier,
            slug: carrierSlug,
            trackingUrlTemplate: shipment.carrierTrackingUrl || '',
            supportPhone: '+91 11 2345 6789',
            supportEmail: 'support@indianbooksworldwide.com',
            averageDeliveryDays: '2-4 business days',
            logo: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=120&auto=format&fit=crop&q=80',
        };
        const trackingUrl = shipment.carrierTrackingUrl || carrierInfo.trackingUrlTemplate.replace('{trackingNumber}', shipment.trackingNumber);
        return {
            orderNumber: shipment.order.orderNumber,
            trackingNumber: shipment.trackingNumber,
            carrier: shipment.carrier,
            carrierSlug: shipment.carrierSlug,
            carrierTrackingUrl: trackingUrl,
            carrierInfo,
            status: shipment.status,
            statusLabel: getStatusLabel(shipment.status),
            currentLocation: shipment.currentLocation || 'In Transit',
            orderDate: shipment.order.createdAt,
            shippedAt: shipment.shippedAt,
            deliveredAt: shipment.deliveredAt,
            estimatedDelivery: shipment.estimatedDelivery || new Date(shipment.createdAt.getTime() + 3 * 24 * 60 * 60 * 1000),
            signedBy: shipment.signedBy,
            destinationCity: shipment.order.shippingAddress.city,
            destinationState: shipment.order.shippingAddress.state,
            destinationPostalCode: shipment.order.shippingAddress.postalCode,
            destinationCountry: shipment.order.shippingAddress.country,
            maskedRecipient: `${shipment.order.shippingAddress.fullName.slice(0, 2)}**** ${shipment.order.shippingAddress.fullName.split(' ').slice(-1)[0] || ''}`,
            items: shipment.order.items.map((item) => ({
                title: item.variant?.title || item.book.title,
                format: item.variant?.format || item.book.binding || 'Book',
                quantity: item.quantity,
                coverImage: item.book.coverImage,
            })),
            timeline: shipment.events.map((ev) => ({
                id: ev.id,
                status: ev.status,
                title: ev.title,
                description: ev.description,
                location: ev.location,
                timestamp: ev.timestamp,
                source: ev.source,
            })),
        };
    }
    /**
     * Create or update a shipment for an Order (Admin / System)
     */
    static async createOrUpdateShipment(data) {
        const slug = (data.carrierSlug || data.carrier.toLowerCase().replace(/[^a-z0-9]/g, '')).toLowerCase();
        const carrierData = exports.SUPPORTED_CARRIERS[slug];
        const carrierTrackingUrl = data.carrierTrackingUrl || (carrierData ? carrierData.trackingUrlTemplate.replace('{trackingNumber}', data.trackingNumber) : undefined);
        const shipment = await database_1.default.shipment.upsert({
            where: { orderId: data.orderId },
            create: {
                orderId: data.orderId,
                trackingNumber: data.trackingNumber,
                carrier: data.carrier,
                carrierSlug: slug,
                carrierTrackingUrl,
                status: data.status || 'DISPATCHED',
                currentLocation: data.currentLocation || 'Main Logistics Hub',
                estimatedDelivery: data.estimatedDelivery,
                shippedAt: data.shippedAt || new Date(),
                events: {
                    create: {
                        status: data.status || 'DISPATCHED',
                        title: `Package Dispatched with ${data.carrier}`,
                        description: `AWB ${data.trackingNumber} generated and package handed over to carrier.`,
                        location: data.currentLocation || 'Fulfillment Center, New Delhi',
                        source: 'ADMIN',
                    },
                },
            },
            update: {
                trackingNumber: data.trackingNumber,
                carrier: data.carrier,
                carrierSlug: slug,
                carrierTrackingUrl,
                status: data.status || undefined,
                currentLocation: data.currentLocation || undefined,
                estimatedDelivery: data.estimatedDelivery || undefined,
                shippedAt: data.shippedAt || undefined,
            },
            include: { events: true },
        });
        // Sync Order Status
        if (data.status === 'DELIVERED') {
            await database_1.default.order.update({
                where: { id: data.orderId },
                data: { status: 'DELIVERED' },
            });
        }
        else if (data.status === 'DISPATCHED' || data.status === 'IN_TRANSIT') {
            await database_1.default.order.update({
                where: { id: data.orderId },
                data: { status: 'SHIPPED' },
            });
        }
        return shipment;
    }
    /**
     * Append a real-time tracking event to a shipment
     */
    static async addTrackingEvent(data) {
        const event = await database_1.default.trackingEvent.create({
            data: {
                shipmentId: data.shipmentId,
                status: data.status,
                title: data.title,
                description: data.description,
                location: data.location,
                timestamp: data.timestamp || new Date(),
                source: data.source || 'SYSTEM',
            },
        });
        // Update shipment current status and location
        await database_1.default.shipment.update({
            where: { id: data.shipmentId },
            data: {
                status: data.status,
                currentLocation: data.location || undefined,
                deliveredAt: data.status === 'DELIVERED' ? new Date() : undefined,
            },
        });
        return event;
    }
    /**
     * Process Carrier Webhooks (Delhivery, Shiprocket, BlueDart, DHL)
     */
    static async processCarrierWebhook(carrierSlug, payload) {
        const slug = carrierSlug.toLowerCase();
        let trackingNumber = '';
        let status = '';
        let eventTitle = '';
        let eventDesc = '';
        let location = '';
        let timestamp = new Date();
        // Universal normalization per courier format
        if (slug === 'delhivery') {
            trackingNumber = payload.waybill || payload.awb || payload.Shipment?.AWB || '';
            status = mapCarrierStatus(payload.Status?.Status || payload.status || '');
            eventTitle = payload.Status?.StatusType || payload.Status?.Status || 'Delhivery Status Update';
            eventDesc = payload.Status?.Instructions || payload.Status?.StatusLocation || '';
            location = payload.Status?.StatusLocation || payload.location || '';
            if (payload.Status?.StatusDateTime)
                timestamp = new Date(payload.Status.StatusDateTime);
        }
        else if (slug === 'shiprocket') {
            trackingNumber = payload.awb || payload.awb_code || '';
            status = mapCarrierStatus(payload.current_status || payload.status || '');
            eventTitle = payload.current_status || 'Shiprocket Transit Event';
            eventDesc = payload.activity || payload.scans?.[0]?.activity || '';
            location = payload.scans?.[0]?.location || '';
        }
        else if (slug === 'bluedart') {
            trackingNumber = payload.awbNo || payload.AWBNo || '';
            status = mapCarrierStatus(payload.status || '');
            eventTitle = payload.statusDesc || 'Blue Dart Status Update';
            location = payload.statusLocation || '';
        }
        else {
            // Generic Webhook format
            trackingNumber = payload.trackingNumber || payload.tracking_number || payload.awb || '';
            status = mapCarrierStatus(payload.status || payload.event || 'IN_TRANSIT');
            eventTitle = payload.title || payload.message || `Carrier Update (${slug})`;
            eventDesc = payload.description || payload.details || '';
            location = payload.location || payload.hub || '';
        }
        if (!trackingNumber) {
            throw new Error(`Webhook payload missing AWB / tracking number for carrier "${slug}".`);
        }
        const shipment = await database_1.default.shipment.findUnique({
            where: { trackingNumber },
        });
        if (!shipment) {
            throw new Error(`Shipment with AWB ${trackingNumber} not found.`);
        }
        // Add tracking event and update status
        const event = await this.addTrackingEvent({
            shipmentId: shipment.id,
            status,
            title: eventTitle,
            description: eventDesc,
            location,
            timestamp,
            source: 'CARRIER_WEBHOOK',
        });
        // Store raw webhook payload for audit logs
        await database_1.default.shipment.update({
            where: { id: shipment.id },
            data: {
                rawWebhookData: payload,
            },
        });
        return {
            success: true,
            trackingNumber,
            carrier: slug,
            status,
            eventId: event.id,
        };
    }
    /**
     * Get supported carriers list with metadata
     */
    static getSupportedCarriers() {
        return Object.values(exports.SUPPORTED_CARRIERS);
    }
}
exports.TrackingService = TrackingService;
function mapCarrierStatus(raw) {
    const norm = raw.toUpperCase().replace(/[^A-Z]/g, '_');
    if (norm.includes('DELIVERED') || norm.includes('DLVD'))
        return 'DELIVERED';
    if (norm.includes('OUT_FOR_DELIVERY') || norm.includes('OFD'))
        return 'OUT_FOR_DELIVERY';
    if (norm.includes('IN_TRANSIT') || norm.includes('TRANSIT') || norm.includes('DISPATCH'))
        return 'IN_TRANSIT';
    if (norm.includes('PICKED') || norm.includes('MANIFEST') || norm.includes('RTO_INITIATED'))
        return 'PROCESSING';
    if (norm.includes('FAILED') || norm.includes('UNDELIVERED') || norm.includes('EXCEPTION'))
        return 'EXCEPTION';
    return 'IN_TRANSIT';
}
function getStatusLabel(status) {
    switch (status) {
        case 'ORDER_PLACED':
            return 'Order Placed & Confirmed';
        case 'PROCESSING':
            return 'Processing & Archival Packaging in Progress';
        case 'DISPATCHED':
            return 'Dispatched & Handed Over to Carrier';
        case 'IN_TRANSIT':
            return 'In Transit — Moving between Regional Hubs';
        case 'OUT_FOR_DELIVERY':
            return 'Out for Delivery — Expected Today';
        case 'DELIVERED':
            return 'Successfully Delivered';
        case 'EXCEPTION':
            return 'Delivery Attempt Exception / Re-route in Progress';
        default:
            return 'Shipment in Transit';
    }
}
//# sourceMappingURL=tracking.service.js.map