import { DateTime } from 'luxon'
import { beforeSave, BaseModel, belongsTo, column } from '@adonisjs/lucid/orm'
import type { BelongsTo } from '@adonisjs/lucid/types/relations'
import Order from './order.js'
import InternationalCity from './international_city.js'
import MasterDataCountry from './master_data_country.js'

export default class InternationalOrder extends BaseModel {
  @column({ isPrimary: true })
  declare id: number

  @column()
  declare order_id: number

  @belongsTo(() => Order, { localKey: 'id', foreignKey: 'order_id' })
  declare order_details: BelongsTo<typeof Order>

  // Shipper Details
  @column()
  declare shipper_company_name: string | null

  @column()
  declare shipper_name: string | null

  @column()
  declare shipper_address: string | null

  @column()
  declare shipper_city: string | null

  @column()
  declare shipper_city_id: number | null

  @belongsTo(() => InternationalCity, { foreignKey: 'shipper_city_id' })
  declare shipper_city_details: BelongsTo<typeof InternationalCity>

  @column()
  declare shipper_postal_code: string | null

  @column()
  declare shipper_country: string | null

  @column()
  declare shipper_country_id: number | null

  @belongsTo(() => MasterDataCountry, { foreignKey: 'shipper_country_id' })
  declare shipper_country_details: BelongsTo<typeof MasterDataCountry>

  @column()
  declare shipper_phone: string | null

  @column()
  declare shipper_email: string | null

  @column()
  declare shipper_tax_no: string | null

  @column()
  declare recipient_company_name: string | null

  @column()
  declare recipient_name: string | null

  @column()
  declare recipient_address: string | null

  @column()
  declare recipient_city: string | null

  @column()
  declare recipient_city_id: number | null

  @belongsTo(() => InternationalCity, { foreignKey: 'recipient_city_id' })
  declare recipient_city_details: BelongsTo<typeof InternationalCity>

  @column()
  declare recipient_postal_code: string | null

  @column()
  declare recipient_country: string | null

  @column()
  declare recipient_country_id: number | null

  @belongsTo(() => MasterDataCountry, { foreignKey: 'recipient_country_id' })
  declare recipient_country_details: BelongsTo<typeof MasterDataCountry>

  @column()
  declare recipient_phone: string | null

  @column()
  declare recipient_mobile: string | null

  @column()
  declare recipient_email: string | null

  @column()
  declare recipient_tax_no: string | null

  @column()
  declare currency: string | null

  @column()
  declare customs_value: number | null

  @column()
  declare dhl_account_number: string | null

  @column()
  declare api_key: string | null

  @column()
  declare account_number: string | null

  @column()
  declare account_pin: string | null

  @column()
  declare meter_number: string | null

  @column()
  declare account_entity: string | null

  @column()
  declare account_country_code: string | null

  @column()
  declare product_group: string | null

  @column()
  declare product_type: string | null

  @column()
  declare payment_type: string | null

  @column()
  declare packaging_type: string | null

  @column()
  declare carrier: string | null

  @column()
  declare description: string | null

  @column()
  declare courier_order_tracking_no: string | null

  @column()
  declare courier_order_barcode_url: string | null

  @column()
  declare shipper_response: string | null

  @column()
  declare service_code: string | null

  @column({
    serialize: (value) => {
      return Number(value)
    },
  })
  declare courier_rate: number

  @column({
    serialize: (value) => {
      return Number(value)
    },
  })
  declare margin: number

  @column.dateTime({ autoCreate: true })
  declare created_at: DateTime

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  declare updated_at: DateTime

  @beforeSave()
  public static async synchronizeNamesAndIds(order: InternationalOrder) {
    // Shipper City
    if (order.shipper_city_id && !order.shipper_city) {
      const city = await InternationalCity.find(order.shipper_city_id)
      if (city) order.shipper_city = city.name
    } else if (!order.shipper_city_id && order.shipper_city) {
      const city = await InternationalCity.query().where('name', order.shipper_city).first()
      if (city) order.shipper_city_id = Number(city.id)
    }

    // Shipper Country
    if (order.shipper_country_id && !order.shipper_country) {
      const country = await MasterDataCountry.find(order.shipper_country_id)
      if (country) order.shipper_country = country.name
    } else if (!order.shipper_country_id && order.shipper_country) {
      const country = await MasterDataCountry.query()
        .where('name', order.shipper_country)
        .orWhere('short_code', order.shipper_country)
        .first()
      if (country) order.shipper_country_id = Number(country.id)
    }

    // Recipient City
    if (order.recipient_city_id && !order.recipient_city) {
      const city = await InternationalCity.find(order.recipient_city_id)
      if (city) order.recipient_city = city.name
    } else if (!order.recipient_city_id && order.recipient_city) {
      const city = await InternationalCity.query().where('name', order.recipient_city).first()
      if (city) order.recipient_city_id = Number(city.id)
    }

    // Recipient Country
    if (order.recipient_country_id && !order.recipient_country) {
      const country = await MasterDataCountry.find(order.recipient_country_id)
      if (country) order.recipient_country = country.name
    } else if (!order.recipient_country_id && order.recipient_country) {
      const country = await MasterDataCountry.query()
        .where('name', order.recipient_country)
        .orWhere('short_code', order.recipient_country)
        .first()
      if (country) order.recipient_country_id = Number(country.id)
    }
  }

  public static async attachCityDetails(order: InternationalOrder | null) {
    if (!order) return
    /* ----------------- Collect names ----------------- */

    const cityNames = [order.shipper_city, order.recipient_city].filter(Boolean) as string[]

    const countryNames = [order.shipper_country, order.recipient_country].filter(
      Boolean
    ) as string[]

    /* ----------------- Fetch cities ------------------ */

    const cities = cityNames.length
      ? await InternationalCity.query().whereIn('name', cityNames)
      : []

    const cityMap = new Map(cities.map((c) => [c.name, c]))

    /* ---------------- Fetch countries ---------------- */

    const countries = countryNames.length
      ? await MasterDataCountry.query()
          .whereIn('name', countryNames)
          .orWhereIn('short_code', countryNames)
      : []

    const countryMap = new Map(
      countries.flatMap((c) => [
        [c.name, c],
        [c.short_code, c],
      ])
    )

    /* ----------------- Format helpers ---------------- */

    const formatCountry = (country?: MasterDataCountry | null) =>
      country
        ? {
            id: country.id,
            name: country.name,
            short_code: country.short_code,
            phone_code: country.phone_code,
            iso_code: country.iso_code,
          }
        : null

    const formatCity = (city?: InternationalCity | null) =>
      city
        ? {
            id: city.id,
            name: city.name,
          }
        : null

    /* ----------------- Shipper ----------------- */

    let shipperCity = null
    if (order.shipper_city_id) {
      shipperCity = await InternationalCity.find(order.shipper_city_id)
    } else {
      shipperCity = cityMap.get(order.shipper_city || '')
    }

    let shipperCountry = null
    if (order.shipper_country_id) {
      shipperCountry = await MasterDataCountry.find(order.shipper_country_id)
    } else {
      shipperCountry =
        countryMap.get(shipperCity?.country_name || '') ||
        countryMap.get(order.shipper_country || '')
    }

    order.$extras.shipper_city_details = formatCity(shipperCity)
    order.$extras.shipper_country_details = formatCountry(shipperCountry)

    /* ---------------- Recipient ---------------- */

    let recipientCity = null
    if (order.recipient_city_id) {
      recipientCity = await InternationalCity.find(order.recipient_city_id)
    } else {
      recipientCity = cityMap.get(order.recipient_city || '')
    }

    let recipientCountry = null
    if (order.recipient_country_id) {
      recipientCountry = await MasterDataCountry.find(order.recipient_country_id)
    } else {
      recipientCountry =
        countryMap.get(recipientCity?.country_name || '') ||
        countryMap.get(order.recipient_country || '')
    }

    order.$extras.recipient_city_details = formatCity(recipientCity)
    order.$extras.recipient_country_details = formatCountry(recipientCountry)
  }
}
