import {
  ShippingProviderContract,
  ShipmentResult,
  TrackingResult,
  RateResult,
} from './shipping_interface.js'
import Order from '#models/order'
import shippingConfig from '#config/shipping'
import logger from '@adonisjs/core/services/logger'
import InternationalOrder from '#models/international_order'
import { money, normalizeAramexCity } from '../../Helper/Helper.js'

export default class AramexService implements ShippingProviderContract {
  private config = shippingConfig.aramex

  private getClientInfo() {
    return {
      UserName: this.config.username,
      Password: this.config.password,
      Version: 'v1.0',
      AccountNumber: this.config.accountNumber,
      AccountPin: this.config.accountPin,
      AccountEntity: this.config.accountEntity,
      AccountCountryCode: this.config.accountCountryCode,
      Source: 24,
    }
  }

  async createShipment(
    order: Order,
    internationalOrder?: InternationalOrder
  ): Promise<ShipmentResult> {
    try {
      const payload = this.prepareShipmentPayload(order, internationalOrder)
      const response = await fetch(
        `${this.config.baseUrl}/Shipping/Service_1_0.svc/json/CreateShipments`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
          },
          body: JSON.stringify(payload),
        }
      )

      if (!response.ok) {
        console.log(response)
        const errorBody = await response.text()
        logger.error({ errorBody }, 'Aramex Create Shipment Failed')
        throw new Error(`Aramex API Error: ${response.statusText}`)
      }

      const data: any = await response.json()

      if (data.HasErrors) {
        const notifications =
          data.Notifications?.map((n: any) => n.Message).join(', ') ||
          data.Shipments?.[0]?.Notifications?.map((n: any) => n.Message).join(', ') ||
          'Unknown Aramex validation error'

        logger.error(JSON.stringify(data, null, 2), 'Aramex CreateShipment Full Error Response')

        throw new Error(`Aramex Error: ${notifications}${JSON.stringify(payload)}`)
      }

      const shipment = data.Shipments?.[0]
      const shipmentId = shipment?.ID
      const labelUrl = shipment?.ShipmentLabel?.LabelURL

      return {
        trackingNumber: shipmentId,
        labelUrl: labelUrl,
        provider: 'Aramex',
        apiResponse: data,
        // Cost might not be returned directly in this call depending on account setup
      }
    } catch (error) {
      logger.error(error, 'Aramex Create Shipment Error')
      throw error
    }
  }

  async trackShipment(trackingNumber: string): Promise<TrackingResult> {
    try {
      const payload = {
        ClientInfo: this.getClientInfo(),
        Shipments: [trackingNumber],
      }

      const response = await fetch(
        `${this.config.baseUrl}/Tracking/Service_1.0.svc/json/TrackShipments`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
          },
          body: JSON.stringify(payload),
        }
      )

      if (!response.ok) {
        throw new Error(`Aramex Tracking Failed: ${response.statusText}`)
      }

      const data: any = await response.json()
      if (data.HasErrors) {
        throw new Error(`Aramex Tracking Error: ${data.Notifications?.[0]?.Message}`)
      }

      const trackingResult = data.TrackingResults?.[0]?.Value
      const history = trackingResult?.TrackingUpdateHistory || []

      return {
        trackingNumber: trackingNumber,
        status: trackingResult?.WaybillCondition?.Description || 'UNKNOWN',
        history: history.map((event: any) => ({
          status: event.UpdateCode,
          location: event.UpdateLocation,
          timestamp: event.UpdateDateTime,
          description: event.UpdateDescription,
        })),
      }
    } catch (error) {
      logger.error(error, 'Aramex Track Shipment Error')
      throw error
    }
  }

  async cancelShipment(_trackingNumber: string): Promise<boolean> {
    // Implement if needed, usually not straightforward via simple JSON API
    return false
  }

  async generateLabel(trackingNumber: string): Promise<string> {
    try {
      const payload = {
        ClientInfo: this.getClientInfo(),
        ShipmentNumber: trackingNumber,
      }

      const response = await fetch(
        `${this.config.baseUrl}/Shipping/Service_1.0.svc/json/PrintLabel`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
          },
          body: JSON.stringify(payload),
        }
      )

      if (!response.ok) {
        throw new Error(`Aramex Print Label Failed: ${response.statusText}`)
      }

      const data: any = await response.json()
      if (data.HasErrors) {
        throw new Error(`Aramex Label Error: ${data.Notifications?.[0]?.Message}`)
      }

      return data.ShipmentLabel?.LabelURL || ''
    } catch (error) {
      logger.error(error, 'Aramex Generate Label Error')
      throw error
    }
  }

  async calculateRate(order: Order): Promise<RateResult> {
    try {
      const payload = this.prepareRatePayload(order)
      const response = await fetch(
        `${this.config.baseUrl}/RateCalculator/Service_1.0.svc/json/CalculateRate`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
          },
          body: JSON.stringify(payload),
        }
      )

      if (!response.ok) {
        throw new Error(`Aramex Rate Failed: ${response.statusText}`)
      }

      const data: any = await response.json()
      if (data.HasErrors) {
        throw new Error(`Aramex Rate Error: ${data.Notifications?.[0]?.Message}`)
      }

      return {
        amount: data.TotalAmount?.Value,
        currency: data.TotalAmount?.CurrencyCode,
        provider: 'Aramex',
      }
    } catch (error) {
      logger.error(error, 'Aramex Calculate Rate Error')
      throw error
    }
  }

  private prepareRatePayload(order: Order) {
    return {
      ClientInfo: this.getClientInfo(),
      OriginAddress: {
        Line1: order.pickup_road_id?.toString() || 'Road',
        City: 'Manama',
        CountryCode: 'BH',
      },
      DestinationAddress: {
        Line1: order.destination_road_id?.toString() || 'Road',
        City: 'Riyadh',
        CountryCode: 'SA',
      },
      ShipmentDetails: {
        Dimensions: null,
        ActualWeight: {
          Value: order.total_weight,
          Unit: 'KG',
        },
        ChargeableWeight: null,
        DescriptionOfGoods: 'General Goods',
        GoodsOriginCountry: 'BH',
        NumberOfPieces: order.total_no_of_packages,
        ProductGroup: 'EXP',
        ProductType: 'PDX',
        PaymentType: 'P',
        PaymentOptions: '',
        CustomsValueAmount: null,
      },
    }
  }

  private prepareShipmentPayload(order: Order, internationalOrder?: InternationalOrder) {
    const internationalDetails =
      internationalOrder || (order.international_order_details as unknown as InternationalOrder)

    // Helper to format date for Aramex (ASP.NET AJAX format)
    const formatAramexDate = (date: Date) => `/Date(${date.getTime()})/`
    const currency = 'BHD' // MUST match Aramex account country

    const productType = this.mapProductType(internationalDetails?.product_type)
    const customsValue = Number(internationalDetails?.customs_value || 0)
    const isDutiable = !['PDX', 'EDX'].includes(productType)
    const finalCustomsValue = isDutiable && customsValue <= 0 ? 1 : customsValue

    return {
      ClientInfo: this.getClientInfo(),
      LabelInfo: {
        ReportID: 9201,
        ReportType: 'URL',
      },
      Shipments: [
        {
          Reference1: `ORDER-${order.generated_order_id || order.id}`,
          Reference2: '',
          Reference3: '',
          Shipper: {
            Reference1: `REF-${order.id}`,
            Reference2: '',
            AccountNumber: this.config.accountNumber,
            PartyAddress: {
              Line1: internationalDetails?.shipper_address || order.sender_address || '',
              Line2: '',
              Line3: '',
              City: normalizeAramexCity(internationalDetails?.shipper_city || 'Manama'),
              StateOrProvinceCode: '',
              PostCode: internationalDetails?.shipper_postal_code || '000',
              CountryCode:
                internationalDetails?.shipper_country_details?.short_code ||
                (internationalDetails?.shipper_country?.length === 2
                  ? internationalDetails.shipper_country
                  : 'BH'),
              Longitude: 0,
              Latitude: 0,
              BuildingNumber: null,
              BuildingName: null,
              Floor: null,
              Apartment: null,
              POBox: null,
              Description: null,
            },
            // PartyAddress: {
            //   Line1: internationalDetails?.shipper_address || order.sender_address || 'Test Address',
            //   Line2: 'NA',
            //   Line3: 'NA',
            //   City: 'Manama',
            //   StateOrProvinceCode: '',
            //   PostCode: internationalDetails?.shipper_postal_code || '000',
            //   CountryCode: 'BH',
            // },
            // Contact: {
            //   Department: '',
            //   PersonName: internationalDetails?.shipper_name || order.pickup_customer_name || 'Test Shipper',
            //   Title: '',
            //   CompanyName: internationalDetails?.shipper_company_name || 'Test Company',
            //   PhoneNumber1: internationalDetails?.shipper_phone || '+97336000000',
            //   PhoneNumber1Ext: '',
            //   PhoneNumber2: internationalDetails?.shipper_phone || '+97336000000', // 🔥 REQUIRED
            //   PhoneNumber2Ext: '',
            //   FaxNumber: '',
            //   CellPhone: internationalDetails?.shipper_phone || '+97336000000',
            //   EmailAddress: internationalDetails?.shipper_email || 'shipper@test.com',
            //   Type: '',
            // },

            Contact: {
              Department: null,
              PersonName: internationalDetails?.shipper_name || order.pickup_customer_name,
              Title: null,
              CompanyName: internationalDetails?.shipper_company_name || order.pickup_customer_name,
              PhoneNumber1: internationalDetails?.shipper_phone || order.pickup_mobile_number,
              PhoneNumber1Ext: '',
              PhoneNumber2: '',
              PhoneNumber2Ext: '',
              FaxNumber: null,
              CellPhone: internationalDetails?.shipper_phone || order.pickup_mobile_number,
              EmailAddress: internationalDetails?.shipper_email || 'shipper@example.com',
              Type: '',
            },
          },
          Consignee: {
            Reference1: `REF-${order.id}`,
            Reference2: '',
            AccountNumber: null,
            PartyAddress: {
              Line1: internationalDetails?.recipient_address || order.destination_address || '',
              Line2: '',
              Line3: '',
              City: normalizeAramexCity(internationalDetails?.recipient_city || 'Riyadh'),
              StateOrProvinceCode: '',
              PostCode: internationalDetails?.recipient_postal_code || '000',
              CountryCode:
                internationalDetails?.recipient_country_details?.short_code ||
                (internationalDetails?.recipient_country?.length === 2
                  ? internationalDetails.recipient_country
                  : 'SA'),
              Longitude: 0,
              Latitude: 0,
              BuildingNumber: null,
              BuildingName: null,
              Floor: null,
              Apartment: null,
              POBox: null,
              Description: null,
            },
            Contact: {
              Department: null,
              PersonName: internationalDetails?.recipient_name || order.destination_customer_name,
              Title: null,
              CompanyName:
                internationalDetails?.recipient_company_name || order.destination_customer_name,
              PhoneNumber1:
                internationalDetails?.recipient_phone || order.destination_mobile_number,
              PhoneNumber1Ext: '',
              PhoneNumber2: '',
              PhoneNumber2Ext: '',
              FaxNumber: null,
              CellPhone: internationalDetails?.recipient_phone || order.destination_mobile_number,
              EmailAddress: internationalDetails?.recipient_email || 'consignee@example.com',
              Type: '',
            },
            //             PartyAddress: {
            //   Line1: internationalDetails?.recipient_address || order.destination_address || 'Test Address',
            //   Line2: 'NA',
            //   Line3: 'NA',
            //   City: 'Riyadh',
            //   StateOrProvinceCode: '',
            //   PostCode: internationalDetails?.recipient_postal_code || '11564',
            //   CountryCode: 'SA',
            // },
            // Contact: {
            //   Department: '',
            //   PersonName:
            //     internationalDetails?.recipient_name || order.destination_customer_name || 'Test Consignee',
            //   Title: '',
            //   CompanyName:
            //     internationalDetails?.recipient_company_name || 'Test Company',
            //   PhoneNumber1:
            //     internationalDetails?.recipient_phone || '+966500000000',
            //   PhoneNumber1Ext: '',
            //   PhoneNumber2:
            //     internationalDetails?.recipient_phone || '+966500000000', // 🔥 REQUIRED
            //   PhoneNumber2Ext: '',
            //   FaxNumber: '',
            //   CellPhone:
            //     internationalDetails?.recipient_phone || '+966500000000',
            //   EmailAddress: internationalDetails?.recipient_email || 'consignee@test.com',
            //   Type: '',
            // },
          },
          ThirdParty: null,
          ShippingDateTime: formatAramexDate(new Date()),
          DueDate: formatAramexDate(new Date(Date.now() + 86400000)), // +1 day
          Comments: null,
          PickupLocation: null,
          OperationsInstructions: null,
          AccountingInstrcutions: null,
          Details: {
            Dimensions: null,
            ActualWeight: {
              Unit: 'KG',
              Value: order.total_weight || 0.5,
            },
            ChargeableWeight: {
              Unit: 'KG',
              Value: order.total_weight || 0.5,
            },
            DescriptionOfGoods: internationalDetails?.description || 'General Goods',
            GoodsOriginCountry:
              internationalDetails?.shipper_country_details?.short_code ||
              (internationalDetails?.shipper_country?.length === 2
                ? internationalDetails.shipper_country
                : 'BH'),
            NumberOfPieces: order.total_no_of_packages || 1,
            ProductGroup: internationalDetails?.product_group || 'EXP',
            ProductType: productType,
            PaymentType: internationalDetails?.payment_type || 'P',
            PaymentOptions: '',
            // CustomsValueAmount: {
            //   Unit: internationalDetails?.currency || 'BHD',
            //   Value: internationalDetails?.customs_value || 10,
            // },
            // CashOnDeliveryAmount: null,
            // InsuranceAmount: null,
            // CashAdditionalAmount: null,
            // CashAdditionalAmountDescription: null,
            // CollectAmount: null,
            CustomsValueAmount: money(finalCustomsValue, currency),

            InsuranceAmount: money(0, currency),
            CashOnDeliveryAmount: money(0, currency),
            CollectAmount: money(0, currency),
            Services: '',
            Items:
              order.order_package_list?.map((pkg) => ({
                PackageType: 'Box',
                Quantity: 1,
                Weight: {
                  Unit: 'KG',
                  Value: pkg.weight || 0.5,
                },
                Comments: pkg.package_description || 'Parcel',
                Value: money(
                  isDutiable && (pkg.customer_input_package_value || 0) <= 0
                    ? 1 / (order.order_package_list?.length || 1)
                    : pkg.customer_input_package_value || 0,
                  currency
                ),
              })) || [],
            DeliveryInstructions: null,
            AdditionalProperties: null,
            ContainsDangerousGoods: false,
          },
          Attachments: [],
          ForeignHAWB: null,
          TransportType: 0,
          ShipperReference: `REF-${order.id}`,
          ConsigneeReference: `REF-${order.id}`,
          AdditionalProperties: [
            {
              Name: 'ConsigneeTaxIdVATEINNumber',
              Value: '123456789', // Placeholder or from InternationalOrder
            },
          ],
        },
      ],
    }
  }

  private mapProductType(type?: string | null): string {
    if (!type) return 'PPX'
    const normalized = type.toLowerCase()
    const mapping: Record<string, string> = {
      parcel: 'PPX',
      document: 'PDX',
      ppx: 'PPX',
      pdx: 'PDX',
      epx: 'EPX',
      edx: 'EDX',
      doc: 'PDX',
    }
    return mapping[normalized] || 'PPX'
  }

  async fetchCountries(): Promise<any[]> {
    try {
      const payload = {
        ClientInfo: this.getClientInfo(),
      }

      const response = await fetch(
        `${this.config.baseUrl}/Location/Service_1.0.svc/json/FetchCountries`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
          },
          body: JSON.stringify(payload),
        }
      )

      if (!response.ok) {
        throw new Error(`Aramex Fetch Countries Failed: ${response.statusText}`)
      }

      const data: any = await response.json()
      if (data.HasErrors) {
        throw new Error(`Aramex Fetch Countries Error: ${data.Notifications?.[0]?.Message}`)
      }

      return data.Countries || []
    } catch (error) {
      logger.error(error, 'Aramex Fetch Countries Error')
      throw error
    }
  }

  async fetchCities(countryCode: string): Promise<string[]> {
    try {
      const payload = {
        ClientInfo: this.getClientInfo(),
        CountryCode: countryCode,
      }

      const response = await fetch(
        `${this.config.baseUrl}/Location/Service_1.0.svc/json/FetchCities`,
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
          },
          body: JSON.stringify(payload),
        }
      )

      if (!response.ok) {
        throw new Error(`Aramex Fetch Cities Failed: ${response.statusText}`)
      }

      const data: any = await response.json()
      if (data.HasErrors) {
        throw new Error(`Aramex Fetch Cities Error: ${data.Notifications?.[0]?.Message}`)
      }

      return data.Cities || []
    } catch (error) {
      logger.error(error, 'Aramex Fetch Cities Error')
      throw error
    }
  }

  async calculateInternationalRate(details: {
    width: any
    length: any
    originCity: string
    originCountry: string
    originPostalCode?: string
    destinationCity: string
    destinationCountry: string
    destinationPostalCode?: string
    weight: number
    numberOfPieces: number
    productGroup?: string
    productType?: string
    ShipmentDetails?: any
  }): Promise<RateResult[]> {
    // Determine if it's a document or parcel to select appropriate services
    console.log(details, 'details')
    const isDocument =
      details.productType === 'DOC' ||
      details.productType === 'PDX' ||
      details.ShipmentDetails?.DescriptionOfGoods?.toLowerCase().includes('document')

    const services = isDocument
      ? [
          { code: 'PDX', group: 'EXP', name: 'Express Documents' },
          { code: 'EDX', group: 'EXP', name: 'Economy Documents' },
        ]
      : [
          { code: 'PPX', group: 'EXP', name: 'Express Worldwide' },
          { code: 'EPX', group: 'EXP', name: 'Economy Select' },
        ]

    const ratePromises = services.map(async (service) => {
      try {
        const payload = {
          ClientInfo: {
            UserName: this.config.username,
            Password: this.config.password,
            Version: 'v1.0',
            AccountNumber: this.config.accountNumber,
            AccountPin: this.config.accountPin,
            AccountEntity: this.config.accountEntity,
            AccountCountryCode: this.config.accountCountryCode,
            Source: 24,
          },
          OriginAddress: {
            Line1: details.originCity || 'Manama',
            Line2: '',
            Line3: '',
            City: normalizeAramexCity(details.originCity),
            CountryCode: details.originCountry,
            PostCode: details.originPostalCode || '00000',
          },
          DestinationAddress: {
            Line1: details.destinationCity || 'Thiruvananthapuram',
            Line2: '',
            Line3: '',
            City: normalizeAramexCity(details.destinationCity),
            CountryCode: details.destinationCountry,
            PostCode: details.destinationPostalCode || '695001',
          },
          PreferredCurrencyCode: 'BHD',
          ShipmentDetails: {
            Dimensions: {
              Length: details.length || 10,
              Width: details.width || 10,
              Height: details.width || 10, // Assuming height is passed or defaulting
              Unit: 'CM',
            },
            ActualWeight: { Value: details.weight, Unit: 'KG' },
            ChargeableWeight: { Value: details.weight, Unit: 'KG' },
            DescriptionOfGoods: isDocument ? 'Documents' : 'Parcels',
            GoodsOriginCountry: details.originCountry,
            NumberOfPieces: details.numberOfPieces || 1,
            ProductGroup: service.group,
            ProductType: service.code,
            PaymentType: 'P',
            PaymentOptions: 'Prepaid',
          },
        }

        const response = await fetch(
          `${this.config.baseUrl}/RateCalculator/Service_1_0.svc/json/CalculateRate`,
          {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'Accept': 'application/json',
            },
            body: JSON.stringify(payload),
          }
        )

        if (!response.ok) {
          const errText = await response.text()
          logger.error({ errText, service: service.name }, 'Aramex Rate Failed for Service')
          return null
        }

        const data: any = await response.json()
        if (data.HasErrors) {
          // Log warning but don't throw, so other services might succeed
          logger.warn(
            { errors: data.Notifications, service: service.name },
            'Aramex Rate Error for Service'
          )
          return null
        }

        return {
          amount: data.TotalAmount?.Value,
          currency: data.TotalAmount?.CurrencyCode,
          provider: 'Aramex',
          carrier: 'Aramex',
          service_name: service.name,
          service_code: service.code,
          delivery_date: '',
          delivery_days: 0,
          // estimatedDeliveryDate: new Date(Date.now() + 86400000 * 3).toISOString(), // +3 days approx
          details: data,
        } as any // Cast to any to allow extra fields not in RateResult interface
      } catch (error) {
        logger.error({ error, service: service.name }, 'Aramex Calculate Rate Error')
        return null
      }
    })

    const results = await Promise.all(ratePromises)
    return results.filter((r) => r !== null) as RateResult[]
  }
}
