const axios = require('axios');
const config = require('../config');

/**
 * Service for handling shipping operations with EasyPost API
 */
const shippingService = {
  /**
   * Create a shipment in EasyPost and get available rates with proper IDs
   * @param {Object} addressFrom - Shipping origin address
   * @param {Object} addressTo - Customer shipping address
   * @param {Object} parcelDetails - Package dimensions and weight
   * @returns {Promise<Object>} Object containing shipment details and available rates
   */
  async getShippingRates(addressFrom, addressTo, parcelDetails) {
    // If EasyPost is not enabled, return flat rate shipping
    if (!config.shipping.easypostEnabled || !config.shipping.easypostApiKey) {
      console.log("EASY POST NOT CONFIGURED ", !config.shipping.easypostEnabled, !config.shipping.easypostApiKey)
      return {
        shipment_id: null,
        rates: this.getFlatRateShipping(parcelDetails.order_total)
      };
    }

    try {
      // Format addresses for EasyPost
      const fromAddress = this.formatAddress(addressFrom || config.shipping.originAddress);
      const toAddress = this.formatAddress(addressTo);
      
      // Format parcel for EasyPost
      const parcel = this.formatParcel(parcelDetails);
      
      // Create shipment first to get proper rate IDs (using v2 API)
      const response = await axios.post(
        'https://api.easypost.com/v2/shipments',
        {
          shipment: {
            from_address: fromAddress,
            to_address: toAddress,
            parcel: parcel
          }
        },
        {
          auth: {
            username: config.shipping.easypostApiKey,
            password: ''
          },
          headers: {
            'Content-Type': 'application/json'
          }
        }
      );
      
      const shipment = response.data;
      console.log("Shipment created successfully:", shipment.id);
      
      // Process and filter rates from the shipment object
      const formattedRates = this.processShippingRates(shipment.rates, parcelDetails.order_total);
      
      // Return both the shipment ID and the rates
      return {
        shipment_id: shipment.id,
        rates: formattedRates
      };
    } catch (error) {
      console.error('EasyPost API error:', error.response?.data || error.message);
      // Fallback to flat rate if API fails
      return {
        shipment_id: null,
        rates: this.getFlatRateShipping(parcelDetails.order_total)
      };
    }
  },
  
  /**
   * Purchase a selected rate for an existing shipment
   * @param {string} shipmentId - The EasyPost shipment ID
   * @param {string} rateId - The ID of the selected rate
   * @returns {Promise<Object>} Purchased shipment details
   */
  async purchaseShipment(shipmentId, rateId) {
    // If EasyPost is not enabled or we don't have a shipment ID, return a simulated shipment
    if (!config.shipping.easypostEnabled || !config.shipping.easypostApiKey || !shipmentId) {
      console.log("Cannot purchase shipment - EasyPost not configured or no shipment ID");
      return this.createSimulatedShipment(rateId);
    }

    try {
      // Buy the selected rate
      const buyResponse = await axios.post(
        `https://api.easypost.com/v2/shipments/${shipmentId}/buy`,
        {
          rate: {
            id: rateId
          }
        },
        {
          auth: {
            username: config.shipping.easypostApiKey,
            password: ''
          },
          headers: {
            'Content-Type': 'application/json'
          }
        }
      );
      
      const purchasedShipment = buyResponse.data;
      console.log("Rate purchased successfully:", purchasedShipment.id);
      
      // Return the important details
      return {
        shipment_id: purchasedShipment.id,
        tracking_code: purchasedShipment.tracking_code,
        label_url: purchasedShipment.postage_label.label_url,
        selected_rate: {
          id: purchasedShipment.selected_rate.id,
          carrier: purchasedShipment.selected_rate.carrier,
          service: purchasedShipment.selected_rate.service,
          rate: parseFloat(purchasedShipment.selected_rate.rate),
          delivery_days: purchasedShipment.selected_rate.delivery_days || 'Unknown',
          delivery_date: purchasedShipment.selected_rate.delivery_date || null
        },
        carrier: purchasedShipment.selected_rate.carrier,
        service: purchasedShipment.selected_rate.service,
        created_at: purchasedShipment.created_at,
        status: purchasedShipment.status
      };
    } catch (error) {
      console.error('EasyPost API error during purchasing shipment:', error.response?.data || error.message);
      
      // Return a fallback simulated shipment
      return this.createSimulatedShipment(rateId);
    }
  },
  
  /**
   * Create a simulated shipment when EasyPost is not available
   * @param {string} rateId - The ID of the selected rate 
   * @returns {Object} Simulated shipment details
   */
  createSimulatedShipment(rateId) {
    // Generate a random tracking number
    const trackingNumber = `SIMSHIP${Math.floor(Math.random() * 1000000000)}`;
    
    // Return a simulated shipment
    return {
      shipment_id: `sim_${Date.now()}`,
      tracking_code: trackingNumber,
      label_url: null,
      selected_rate: {
        id: rateId,
        carrier: rateId.includes('flat') ? 'Standard' : 'Simulated',
        service: rateId.includes('flat') ? 'Flat Rate Shipping' : 'Standard Service',
        rate: rateId.includes('free') ? 0 : config.shipping.flatRate,
        delivery_days: '5-7',
        delivery_date: null
      },
      carrier: rateId.includes('flat') ? 'Standard' : 'Simulated',
      service: rateId.includes('flat') ? 'Flat Rate Shipping' : 'Standard Service',
      created_at: new Date().toISOString(),
      status: 'simulated'
    };
  },
  
  /**
   * Format address for EasyPost API
   * @param {Object} address - Address details
   * @returns {Object} Formatted address object
   */
  formatAddress(address) {
    return {
      street1: address.street || address.street1,
      city: address.city,
      state: address.state || address.province,
      zip: address.zip || address.postalCode,
      country: address.country,
      name: address.name || undefined,
      company: address.company || undefined,
      phone: address.phone || undefined,
      email: address.email || undefined
    };
  },
  
  /**
   * Format parcel for EasyPost API
   * @param {Object} parcelDetails - Package dimensions and weight
   * @returns {Object} Formatted parcel object
   */
  formatParcel(parcelDetails) {
    const pkg = config.shipping.defaultPackage;
    
    // Convert weight to ounces if coming from grams
    const weight = parcelDetails.weight || 500; // Default to 500g if not provided
    const weightOz = pkg.weightUnit === 'g' ? weight * 0.035274 : weight;
    
    // Convert dimensions to inches if coming from cm
    const lengthConversionFactor = pkg.unit === 'cm' ? 0.393701 : 1;
    
    return {
      length: (parcelDetails.length || pkg.length) * lengthConversionFactor,
      width: (parcelDetails.width || pkg.width) * lengthConversionFactor,
      height: (parcelDetails.height || pkg.height) * lengthConversionFactor,
      weight: weightOz,
      predefined_package: parcelDetails.predefined_package || null
    };
  },
  
  /**
   * Process and filter shipping rates from EasyPost
   * @param {Array} rates - EasyPost shipping rates
   * @param {number} orderTotal - Order total amount
   * @returns {Array} Processed shipping rates
   */
  processShippingRates(rates, orderTotal) {
    if (!rates || !Array.isArray(rates)) {
      return this.getFlatRateShipping(orderTotal);
    }
    
    // Filter by allowed carriers
    let filteredRates = rates.filter(rate => 
      config.shipping.carriersAllowed.some(carrier => 
        rate.carrier.toUpperCase().replaceAll(' ', '').includes(carrier.toUpperCase().replaceAll(' ', ''))
      )
    );
    
    if (filteredRates.length === 0) {
      return this.getFlatRateShipping(orderTotal);
    }
    
    // Format rates to standardized format - now including the rate ID
    const formattedRates = filteredRates.map(rate => ({
      id: rate.id,
      carrier: rate.carrier,
      service: rate.service,
      rate: parseFloat(rate.rate),
      currency: rate.currency,
      delivery_days: rate.est_delivery_days || rate.delivery_days || 'Unknown',
      delivery_date: rate.delivery_date || null,
      delivery_time: rate.est_delivery_time || null
    }));
    
    // Check if free shipping applies
    if (orderTotal >= config.shipping.freeThreshold) {
      formattedRates.push({
        id: 'free-shipping',
        carrier: 'FREE',
        service: 'Standard Shipping',
        rate: 0,
        currency: 'USD',
        delivery_days: '5-7',
        delivery_date: null,
        delivery_time: null
      });
    }
    
    return formattedRates;
  },
  
  /**
   * Get flat rate shipping as fallback
   * @param {number} orderTotal - Order total amount
   * @returns {Array} Flat rate shipping options
   */
  getFlatRateShipping(orderTotal) {
    const shippingOptions = [{
      id: 'flat-rate',
      carrier: 'Standard',
      service: 'Flat Rate Shipping',
      rate: config.shipping.flatRate,
      currency: 'USD',
      delivery_days: '5-7',
      delivery_date: null,
      delivery_time: null
    }];
    
    // Add free shipping if order qualifies
    if (orderTotal >= config.shipping.freeThreshold) {
      shippingOptions.push({
        id: 'free-shipping',
        carrier: 'FREE',
        service: 'Standard Shipping',
        rate: 0,
        currency: 'USD',
        delivery_days: '5-7',
        delivery_date: null,
        delivery_time: null
      });
    }
    
    return shippingOptions;
  },
  
  /**
   * Parse shipping address from string format
   * @param {string} addressString - Shipping address as string
   * @returns {Object} Parsed address object
   */
  parseAddressString(addressString) {
    const lines = addressString.trim().split('\n').map(line => line.trim());
    
    // Try to intelligently parse the address components
    // This is a simplified version - might need enhancement for edge cases
    const parsedAddress = {
      name: lines[0] || '',
      street: lines[1] || '',
      city: '',
      state: '',
      zip: '',
      country: lines[lines.length - 1] || ''
    };
    
    // Try to parse city, state, zip from line 2
    if (lines[2]) {
      const cityStateZip = lines[2].split(',');
      if (cityStateZip.length >= 2) {
        parsedAddress.city = cityStateZip[0].trim();
        
        // Split state and zip
        const stateZip = cityStateZip[1].trim().split(' ');
        if (stateZip.length >= 2) {
          parsedAddress.state = stateZip[0].trim();
          parsedAddress.zip = stateZip.slice(1).join(' ').trim();
        } else {
          parsedAddress.state = stateZip[0].trim();
        }
      } else {
        parsedAddress.city = lines[2];
      }
    }
    
    return parsedAddress;
  },
  
  /**
   * Calculate total shipping weight from cart items
   * @param {Array} items - Cart items
   * @returns {number} Total weight in grams
   */
  calculateTotalWeight(items) {
    return items.reduce((total, item) => {
      const itemWeight = item.weight_grams || 100; 
      return total + (itemWeight * item.quantity);
    }, 0);
  }
};

module.exports = shippingService;