import type { HttpContext } from '@adonisjs/core/http'
import {
  calculateRateValidator,
  calculateRateByCarrierValidator,
} from '../validators/shipping_rates.js'
import {
  calculateShippingChargeWithMarkup,
  InternationalRateParams,
} from '../Helper/shipping_helper.js'
import { ShippingCarrier } from '../../types/enum.js'
import logger from '@adonisjs/core/services/logger'
import ShippingFactory from '#services/shipping/shipping_factory'
import { normalizeFedExRates, resolveLocation } from '../Helper/Helper.js'
import MasterDataCountry from '#models/master_data_country'
import InternationalShipmentCarrier from '#models/international_shipment_carrier'
import env from '#start/env'

export default class ShippingRatesController {
  /**
   * Get rates from all shipping providers
   * POST /shipping/rates/all
   */
  async getAllProviderRates({ auth, request, response }: HttpContext) {
    try {
      const payload = await request.validateUsing(calculateRateValidator)

      const origin = await resolveLocation({
        city: payload.origin_city,
        country: payload.origin_country,
        postalCode: payload.origin_postal_code,
        lat: payload.origin_lat,
        lng: payload.origin_lng,
      })

      const destination = await resolveLocation({
        city: payload.destination_city,
        country: payload.destination_country,
        postalCode: payload.destination_postal_code,
        lat: payload.destination_lat,
        lng: payload.destination_lng,
      })
      if (payload?.origin_country && payload.destination_country) {
        const destinationCountry = await MasterDataCountry.query()
          .where('name', payload.destination_country)
          .first()

        const originCountry = await MasterDataCountry.query()
          .where('name', payload.origin_country)
          .first()

        if (destinationCountry?.short_code && originCountry?.short_code) {
          payload.destination_country = destinationCountry.short_code
          payload.origin_country = originCountry.short_code
        }
      }

      const params: InternationalRateParams = {
        originCity: payload.origin_city,
        originCountry: payload.origin_country,
        originPostalCode: payload?.origin_postal_code ?? origin?.postalCode,
        destinationCity: payload.destination_city,
        destinationCountry: payload.destination_country,
        destinationPostalCode: payload?.destination_postal_code ?? destination?.postalCode,
        weight: payload.weight,
        numberOfPieces: payload.number_of_pieces,
        productGroup: payload.product_group,
        productType: payload.product_type,
        length: payload.length,
        width: payload.width,
        height: payload.height,
      }

      // FedEx Postal Code Validation
      const fedex = ShippingFactory.getProvider(ShippingCarrier.FedEx) as any
      if (params.originPostalCode && params.originCountry) {
        const validation = await fedex.validatePostalCode(
          params.originPostalCode,
          params.originCountry,
          params.originCity
        )
        if (!validation.status) {
          return response.badRequest({
            status: false,
            message:
              validation.message ||
              `Invalid origin postal code: ${params.originPostalCode} for ${params.originCountry}`,
          })
        }
      }

      if (params.destinationPostalCode && params.destinationCountry) {
        const validation = await fedex.validatePostalCode(
          params.destinationPostalCode,
          params.destinationCountry,
          params.destinationCity
        )
        if (!validation.status) {
          return response.badRequest({
            status: false,
            message:
              validation.message ||
              `Invalid destination postal code: ${params.destinationPostalCode} for ${params.destinationCountry}`,
          })
        }
      }

      if (process.env.NODE_ENV === 'test') {
        const { MockRatesService } = await import('../services/shipping/mock_rates_service.js')
        const mockRates = MockRatesService.getAllRates(params)

        return response.ok({
          status: true,
          message: 'Rates fetched successfully (TEST MODE)',
          data: {
            rates: mockRates,
            failed: [],
          },
        })
      }

      // const carriers = [
      //   // ShippingCarrier.Aramex,
      //   ShippingCarrier.DHL,
      //   // ShippingCarrier.FedEx,
      //   // ShippingCarrier.SMSA,
      // ]
      const enabledCarriers = await InternationalShipmentCarrier.query()
        .where('is_enabled', true)
        .select('carrier')

      const carriers = enabledCarriers
        .map((c) => c.carrier)
        .filter((carrier): carrier is ShippingCarrier =>
          Object.values(ShippingCarrier).includes(carrier as ShippingCarrier)
        )
      if (carriers.length === 0) {
        return response.badRequest({
          status: false,
          message: 'No shipping carriers are currently enabled',
        })
      }
      const ratePromises = carriers.map(async (carrier) => {
        try {
          const rate = await calculateShippingChargeWithMarkup(
            carrier,
            params,
            payload?.created_for_id ?? auth?.user?.id
          )
          return {
            carrier,
            success: true,
            rate,
          }
        } catch (error) {
          logger.error(error, `Failed to get rate from ${carrier}`)
          return {
            carrier,
            success: false,
            error: error.message,
          }
        }
      })

      const results = await Promise.all(ratePromises)

      const successfulRates = results
        .filter((r) => r.success)
        .flatMap((r) => {
          if (r.carrier === ShippingCarrier.FedEx) {
            return normalizeFedExRates(r.rate)
          }
          return r.rate // for DHL/Aramex later
        })

      const failedRates = results.filter((r) => !r.success)

      return response.ok({
        status: true,
        message: 'Rates fetched successfully',
        data: {
          rates: successfulRates,
          failed:
            env.get('NODE_ENV') === 'test'
              ? failedRates.map((r) => ({
                  carrier: r.carrier,
                  error: r.error,
                }))
              : [],
        },
      })
    } catch (error) {
      logger.error(error, 'Get all provider rates error')
      return response.badRequest({
        status: false,
        message: 'Failed to fetch rates',
        error: error.message,
      })
    }
  }

  /**
   * Get rate from a specific provider
   * POST /shipping/rates/:carrier
   */
  async getProviderRate({ request, response }: HttpContext) {
    try {
      const payload = await request.validateUsing(calculateRateByCarrierValidator)

      const params: InternationalRateParams = {
        originCity: payload.origin_city,
        originCountry: payload.origin_country,
        originPostalCode: payload.origin_postal_code,
        originLat: payload.origin_lat,
        originLng: payload.origin_lng,
        destinationCity: payload.destination_city,
        destinationCountry: payload.destination_country,
        destinationPostalCode: payload.destination_postal_code,
        destinationLat: payload.destination_lat,
        destinationLng: payload.destination_lng,
        weight: payload.weight,
        numberOfPieces: payload.number_of_pieces,
        productGroup: payload.product_group,
        productType: payload.product_type,
        length: payload.length,
        width: payload.width,
        height: payload.height,
      }

      // FedEx Postal Code Validation
      const fedex = ShippingFactory.getProvider(ShippingCarrier.FedEx) as any
      if (params.originPostalCode && params.originCountry) {
        const validation = await fedex.validatePostalCode(
          params.originPostalCode,
          params.originCountry,
          params.originCity
        )
        if (!validation.status) {
          return response.badRequest({
            status: false,
            message:
              validation.message ||
              `Invalid origin postal code: ${params.originPostalCode} for ${params.originCountry}`,
          })
        }
      }

      if (params.destinationPostalCode && params.destinationCountry) {
        const validation = await fedex.validatePostalCode(
          params.destinationPostalCode,
          params.destinationCountry,
          params.destinationCity
        )
        if (!validation.status) {
          return response.badRequest({
            status: false,
            message:
              validation.message ||
              `Invalid destination postal code: ${params.destinationPostalCode} for ${params.destinationCountry}`,
          })
        }
      }

      const rate = await calculateShippingChargeWithMarkup(
        payload.carrier,
        params,
        payload?.created_for_id
      )

      return response.ok({
        status: true,
        message: 'Rate calculated successfully',
        data: rate,
      })
    } catch (error) {
      logger.error(error, 'Get provider rate error')
      if (error.message.toLowerCase().includes('postal code')) {
        return response.badRequest({
          status: false,
          message: error.message,
        })
      }
      return response.ok({
        status: false,
        message: 'Failed to calculate rate',
      })
    }
  }

  /**
   * Compare rates across all providers (sorted by price)
   * POST /shipping/rates/compare
   */
  async compareRates({ request, response }: HttpContext) {
    try {
      const payload = await request.validateUsing(calculateRateValidator)

      const params: InternationalRateParams = {
        originCity: payload.origin_city,
        originCountry: payload.origin_country,
        originPostalCode: payload.origin_postal_code,
        originLat: payload.origin_lat,
        originLng: payload.origin_lng,
        destinationCity: payload.destination_city,
        destinationCountry: payload.destination_country,
        destinationPostalCode: payload.destination_postal_code,
        destinationLat: payload.destination_lat,
        destinationLng: payload.destination_lng,
        weight: payload.weight,
        numberOfPieces: payload.number_of_pieces,
        productGroup: payload.product_group,
        productType: payload.product_type,
        length: payload.length,
        width: payload.width,
        height: payload.height,
      }

      // Get rates from all providers
      // const carriers = [
      //   ShippingCarrier.Aramex,
      //   ShippingCarrier.DHL,
      //   ShippingCarrier.FedEx,
      //   ShippingCarrier.SMSA,
      // ]
      const enabledCarriers = await InternationalShipmentCarrier.query()
        .where('is_enabled', true)
        .select('carrier')

      const carriers = enabledCarriers
        .map((c) => c.carrier)
        .filter((carrier): carrier is ShippingCarrier =>
          Object.values(ShippingCarrier).includes(carrier as ShippingCarrier)
        )
      if (carriers.length === 0) {
        return response.badRequest({
          status: false,
          message: 'No shipping carriers are currently enabled',
        })
      }

      const ratePromises = carriers.map(async (carrier) => {
        try {
          const rate = await calculateShippingChargeWithMarkup(
            carrier,
            params,
            payload?.created_for_id
          )
          return {
            success: true,
            rate,
          }
        } catch (error) {
          logger.error(error, `Failed to get rate from ${carrier}`)
          return {
            success: false,
            carrier,
          }
        }
      })

      const results = await Promise.all(ratePromises)

      // Filter successful rates and sort by amount (cheapest first)
      const successfulRates = results
        .filter((r) => r.success)
        .map((r) => r.rate!)
        .sort((a: any, b: any) => (a?.amount || 0) - (b?.amount || 0))

      return response.ok({
        status: true,
        message: 'Rates compared successfully',
        data: {
          rates: successfulRates,
          cheapest: successfulRates[0] || null,
          mostExpensive: successfulRates[successfulRates.length - 1] || null,
        },
      })
    } catch (error) {
      logger.error(error, 'Compare rates error')
      return response.badRequest({
        status: false,
        message: 'Failed to compare rates',
        error: error.message,
      })
    }
  }
}
