"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShippingService = void 0;
const database_1 = __importDefault(require("../../../config/database"));
const shipping_provider_factory_1 = require("./shipping-provider.factory");
const logger_1 = require("../../../config/logger");
const library_1 = require("@prisma/client/runtime/library");
class ShippingService {
    /**
     * 1. CREATE SHIPPING ORDER (ORDER SYNC)
     */
    static async syncOrderToShipping(orderId) {
        const order = await database_1.default.order.findUnique({
            where: { id: orderId },
            include: {
                shippingAddress: true,
                user: true,
            },
        });
        if (!order)
            throw new Error('Order not found');
        // Get default shipping provider configured
        let providerConfig = await database_1.default.shippingProvider.findFirst({
            where: { isEnabled: true, defaultProvider: true },
        });
        if (!providerConfig) {
            providerConfig = await database_1.default.shippingProvider.findFirst({
                where: { isEnabled: true },
                orderBy: { priority: 'asc' },
            });
        }
        if (!providerConfig) {
            throw new Error('No active shipping provider configured in settings.');
        }
        const providerClient = await shipping_provider_factory_1.ShippingProviderFactory.getProvider(providerConfig.providerName);
        // Prepare details for delivery sync
        const address = order.shippingAddress;
        const recipientAddressStr = address.street;
        const shipmentDetails = {
            orderId: order.id,
            pickupLocation: providerConfig.pickupLocation || 'Warehouse-Main',
            weight: 0.85, // Default weight estimate
            length: 15,
            width: 15,
            height: 10,
            recipientName: address.fullName,
            recipientAddress: recipientAddressStr,
            recipientCity: address.city,
            recipientState: address.state,
            recipientPincode: address.postalCode,
            recipientPhone: address.phone,
        };
        const syncRes = await providerClient.createShipment(shipmentDetails);
        if (!syncRes.success) {
            throw new Error(syncRes.errorDetails || 'Failed to sync shipping with provider');
        }
        // Save ShippingOrder to database
        const shippingOrder = await database_1.default.shippingOrder.create({
            data: {
                orderId: order.id,
                providerId: providerConfig.id,
                shipmentId: syncRes.shipmentId || `mnl_ship_${Date.now()}`,
                status: syncRes.status || 'PENDING',
                estimatedDelivery: syncRes.estimatedDelivery || null,
                shippingCharges: new library_1.Decimal(order.shippingFee || 0.0),
                weight: new library_1.Decimal(shipmentDetails.weight),
                dimensionsLength: shipmentDetails.length,
                dimensionsWidth: shipmentDetails.width,
                dimensionsHeight: shipmentDetails.height,
            },
        });
        // Create initial Tracking Log
        await database_1.default.shipmentTracking.create({
            data: {
                shippingOrderId: shippingOrder.id,
                status: 'ORDERED',
                location: providerConfig.warehouseName || 'Warehouse Handoff',
                eventDetails: 'Order confirmed and synced for packaging.',
            },
        });
        // Audit logs entry
        await database_1.default.shippingAudit.create({
            data: {
                providerId: providerConfig.id,
                action: 'ORDER_SYNCED',
                performedBy: 'SYSTEM',
                details: `Synced order ${order.orderNumber} with provider: ${providerConfig.displayName}`,
            },
        });
        logger_1.logger.info(`Synced order: ${order.orderNumber} to shipping order ID: ${shippingOrder.id}`);
        return shippingOrder;
    }
    /**
     * 2. GENERATE AWB & ASSIGN COURIER
     */
    static async generateAwb(shippingOrderId) {
        const shippingOrder = await database_1.default.shippingOrder.findUnique({
            where: { id: shippingOrderId },
            include: { provider: true },
        });
        if (!shippingOrder)
            throw new Error('Shipping order not found');
        const providerClient = await shipping_provider_factory_1.ShippingProviderFactory.getProvider(shippingOrder.provider.providerName);
        const awbRes = await providerClient.generateAwb(shippingOrder.shipmentId || '');
        if (!awbRes.success) {
            throw new Error(awbRes.courierName || 'AWB dispatch assignment failed');
        }
        const updated = await database_1.default.shippingOrder.update({
            where: { id: shippingOrderId },
            data: {
                awbNumber: awbRes.awbNumber,
                courierName: awbRes.courierName,
                status: 'READY_TO_SHIP',
            },
        });
        // Append event timeline
        await database_1.default.shipmentTracking.create({
            data: {
                shippingOrderId,
                status: 'READY_TO_SHIP',
                location: shippingOrder.provider.warehouseName,
                eventDetails: `AWB assigned: ${awbRes.awbNumber} via ${awbRes.courierName}. Ready to ship.`,
            },
        });
        // Save label URL attachment
        const labelRes = await providerClient.generateLabel(shippingOrder.shipmentId || '');
        if (labelRes.success) {
            await database_1.default.shippingLabel.create({
                data: {
                    shippingOrderId,
                    labelUrl: labelRes.labelUrl,
                    format: 'PDF',
                },
            });
        }
        // Save commercial shipping invoice
        const invoiceRes = await providerClient.generateInvoice(shippingOrder.shipmentId || '');
        if (invoiceRes.success) {
            await database_1.default.shippingInvoice.create({
                data: {
                    shippingOrderId,
                    invoiceUrl: invoiceRes.invoiceUrl,
                    invoiceType: 'SHIPPING',
                },
            });
        }
        return updated;
    }
    /**
     * 3. DISPATCH PICKUP SCHEDULE
     */
    static async schedulePickup(shippingOrderId, pickupTime) {
        const shippingOrder = await database_1.default.shippingOrder.findUnique({
            where: { id: shippingOrderId },
            include: { provider: true },
        });
        if (!shippingOrder || !shippingOrder.awbNumber) {
            throw new Error('Shipping order not found or AWB number missing.');
        }
        const providerClient = await shipping_provider_factory_1.ShippingProviderFactory.getProvider(shippingOrder.provider.providerName);
        const pickupRes = await providerClient.requestPickup(shippingOrder.awbNumber, pickupTime);
        if (!pickupRes.success) {
            throw new Error(pickupRes.status || 'Failed to schedule pickup');
        }
        // Create Pickup Request
        const pickup = await database_1.default.pickupRequest.create({
            data: {
                shippingOrderId,
                pickupToken: pickupRes.pickupToken,
                pickupTime,
                status: pickupRes.status,
            },
        });
        // Update shipping status
        await database_1.default.shippingOrder.update({
            where: { id: shippingOrderId },
            data: { status: 'PICKUP_SCHEDULED' },
        });
        // Append timeline log
        await database_1.default.shipmentTracking.create({
            data: {
                shippingOrderId,
                status: 'READY_TO_SHIP',
                location: shippingOrder.provider.warehouseName,
                eventDetails: `Pickup scheduled token: ${pickupRes.pickupToken} for timing: ${pickupTime.toISOString()}`,
            },
        });
        return pickup;
    }
    /**
     * 4. CANCEL SHIPMENT DISPATCH
     */
    static async cancelShipment(shippingOrderId) {
        const shippingOrder = await database_1.default.shippingOrder.findUnique({
            where: { id: shippingOrderId },
            include: { provider: true, pickups: true },
        });
        if (!shippingOrder)
            throw new Error('Shipping order not found');
        const providerClient = await shipping_provider_factory_1.ShippingProviderFactory.getProvider(shippingOrder.provider.providerName);
        // Cancel pickups
        for (const pickup of shippingOrder.pickups) {
            if (pickup.pickupToken) {
                await providerClient.cancelPickup(pickup.pickupToken);
                await database_1.default.pickupRequest.update({
                    where: { id: pickup.id },
                    data: { status: 'CANCELLED' },
                });
            }
        }
        // Update status
        await database_1.default.shippingOrder.update({
            where: { id: shippingOrderId },
            data: { status: 'CANCELLED' },
        });
        // Add cancel timeline track
        await database_1.default.shipmentTracking.create({
            data: {
                shippingOrderId,
                status: 'CANCELLED',
                eventDetails: 'Shipment cancellation requested by admin.',
            },
        });
        return { success: true };
    }
    /**
     * 5. TRACK SHIPMENT (REALTIME API POLL)
     */
    static async trackShipment(awbNumber) {
        const shippingOrder = await database_1.default.shippingOrder.findFirst({
            where: { awbNumber },
            include: { provider: true },
        });
        if (!shippingOrder)
            throw new Error('Shipping order not found for this tracking number');
        const providerClient = await shipping_provider_factory_1.ShippingProviderFactory.getProvider(shippingOrder.provider.providerName);
        const trackingRes = await providerClient.trackShipment(awbNumber);
        return trackingRes;
    }
}
exports.ShippingService = ShippingService;
//# sourceMappingURL=shipping.service.js.map