use ../../../../core/nulib/lib_provisioning/utils/format.nu money_conversion

def aws_default_store_type [] {
  "Provisioned IOPS"
}
export def aws_get_price [
  all_data: record
  key: string
  price_col: string = "pricePerUnit"
] { 
  let data = ($all_data | get -o item) 
  let str_price_col = if ($price_col | is-empty) { "pricePerUnit" } else { $price_col }
  let value = ($data | get -o $str_price_col | get -o "USD" | default "") 
  let val = if ($value | is-empty) { 
    0 
  } else { 
    money_conversion "USD" "EUR" ($value | into float)  
  }
  let unit = $"($val) ($data | get -o unit | default "")"
  if ($unit | str contains "Hrs") {
    match $key {
      "month" => (($val * 24) * 30),
      "day" => ($val * 24),
      "hour" => ($val),
      "minute" => ($val / 60),
      "unit" => $unit,
    }
  } else if ($unit | str contains "Mo") {
    match $key {
      "month" => $val,
      "day" => ($val / 30),
      "hour" => (($val / 30) / 24),
      "minute" => ((($val / 30) / 24) / 60),
      "unit" => $unit,
    }
  } else {
    0
  }
}
export def aws_get_provider_path [
  settings: record
  server: record
] {
  let data_path = if ($settings.data.prov_data_dirpath | str starts-with "." ) {
      ($settings.src_path | path join $settings.data.prov_data_dirpath)
  } else { $settings.data.prov_data_dirpath } 
  if not ($data_path | path exists) { mkdir $data_path }
  ($data_path | path join $"($server.provider)_prices.($env.PROVISIONING_WK_FORMAT)")
}
export def aws_get_item_for_server [
  server: record
  settings: record
  cloud_data: record
] {
  let provider_prices_path = (aws_get_provider_path $settings $server)
  if not ($provider_prices_path | path exists) { return {}  }
  let pricing_data = (open $provider_prices_path | default [])
  let memory = $"(($server.reqplan.memory | default 1024) / 1024) GiB"
  let cores = $"($server.reqplan.cores | default 1)"
  let current_gen = if ($server.reqplan.gen | default "") == "current" { "Yes" } else { "No" }
  #let arch = if ($server.reqplan.arch | str contains "x86_64") { "Intel" } else { ""}
  for item in $pricing_data {
    if ($item | get -o data | is-empty) or ($item | get -o plan | is-empty) { continue  }
    if ($item.plan != $server.plan and $item.zone != $server.zone) { continue }
    for it in $item.data {
      if ($it | get -o product | is-empty) { continue  }
      if ( $it.product.attributes.memory == $memory
        and $it.product.attributes.vcpu == $cores
        and $it.product.attributes.currentGeneration == $current_gen
        and ($it.product.attributes.operatingSystem | str contains "Linux")
      ) {
        return ($it.on_demand | get -o priceDimensions | default {})
      }
    }
  }
  {}
} 
export def aws_get_item_for_storage [
  server: record
  settings: record
  cloud_data: record
] {
  let provider_prices_path = (aws_get_provider_path $settings $server)
  if not ($provider_prices_path | path exists) { return [] }
  let pricing_data = (open $provider_prices_path | default [])
  if ($pricing_data | length) == 0 { return [] }
  let default_store_type = aws_default_store_type
  mut $data = []
  for store in ($server | get -o storages | default []) {
    let store_type = ($store | get -o  prov_type | default $default_store_type)
    for item in $pricing_data {
      let item_type = ($item | get -o store | default "")
      if ($item_type | is-empty) or $item_type != $store_type and $item.zone != $server.zone { continue }
      if ($item | get -o data | is-empty) { continue  }
      let item_type = ($item | get -o store | default "")
      return ($item | get  data | get -o 0 | get -o on_demand | get -o priceDimensions | default {})
      # $data = ($data | append ($item | get  data | get -o 0 | get -o on_demand | get -o priceDimensions | default {}))
    }
  }
  {}
  #$data
} 
export def aws_load_infra_servers_info [
  settings: record
  server: record
  error_exit: bool
] { 
  let provider_prices_path = (aws_get_provider_path $settings $server)
  if ($provider_prices_path | path exists) { 
    let pricing_data = (open $provider_prices_path)
    for it in $pricing_data { 
      let zone = ($it | get -o zone | default "")
      let plan = ($it | get -o plan | default "")
      if $zone == $server.zone and $plan == $server.plan { 
        return {plan: $plan, zone: $zone } 
      }
    }
  }
  (aws_load_infra_servers $provider_prices_path  $settings $server)
}
export def aws_load_infra_storages_info [
  settings: record
  server: record
  error_exit: bool
] { 
  let provider_prices_path = (aws_get_provider_path $settings $server)
  if ($provider_prices_path | path exists) { 
    let default_store_type = aws_default_store_type
    let pricing_data = (open $provider_prices_path)
    for it in $pricing_data { 
      let zone = ($it | get -o zone | default "")
      let store = ($it | get -o store | default "")
      if $zone == $server.zone and $store == $default_store_type { 
        return {zone: $zone, store: $store } 
      }
    }
  }
  aws_load_infra_storages $provider_prices_path $settings $server 
}
export def aws_get_price_data [
  filter: record
  server: record
] {
  let res = (^aws pricing get-products --service-code AmazonEC2 --filters 
    $"Type=TERM_MATCH,Field=($filter.field),Value=($filter.value)" $"Type=TERM_MATCH,Field=regionCode,Value=($server.zone)"
    --query "PriceList[]" --region us-east-1 --out json | complete
  ) 
  if $res.exit_code != 0 { 
    print $"❗ Errors on ($server.hostname) ($server.provider) ($server.plan) in ($server.zone) load cloud price data error: ($res.stdout ) "
    return
  }  
  # | str replace '\'  ''| str replace '"{' '{' | str replace  '}"' '}') 
  mut $data = []
  for it in ($res.stdout | from json) { 
    let it_data = ($it | from json)

    let product = ($it_data | get -o product | default {})
    if ($product | is-empty) { continue } 

    #let attributes = ($product | get -o attributes | default {})
    let on_demand_key = ($it_data | get -o terms | get -o OnDemand | columns | first) 
    let on_demand_data = ($it_data | get -o terms | get -o OnDemand | get -o $on_demand_key | default {})
    let price_dimension = if ($on_demand_data | is-not-empty) {
      let price_dimension_key = ($on_demand_data | get -o priceDimensions | columns | first | default "")
      ($on_demand_data | get -o priceDimensions | get -o $price_dimension_key | default {})
    } else { 
      {}
    }
    $data = ( $data | append {
      product: $product,
      on_demand: { 
        priceDimensions: $price_dimension,
        sku:            ($on_demand_data | get -o sku),
        effectiveDate:  ($on_demand_data | get -o effectiveDate),
        offerTermCode: ($on_demand_data | get -o offerTermCode),
        termAttributes: ($on_demand_data | get -o termAttributes)
      }
    }) 
  }
  $data
}
export def aws_load_infra_storages [
  provider_prices_path: string
  settings: record
  server: record
] { 
  let default_store_type = aws_default_store_type
  let curr_data = if ($provider_prices_path | path exists) { 
    (open $provider_prices_path)
  } else { 
    []
  }
  $curr_data | where {|it|
    if $it.zone == $server.zone and $it.store? != null and $it.store == $default_store_type { 
      print $it
      return 
    }
  }
  let filter = { 
    field: "volumeType",
    value: $default_store_type
  }
  let data =  (aws_get_price_data $filter $server)
  let srv_data = { zone: $server.zone, store: $default_store_type, data: $data} 
  let all_data = if ($provider_prices_path | path exists) { 
    (open $provider_prices_path | append $srv_data)
  } else { 
    [$srv_data]
  }
  if $env.PROVISIONING_WK_FORMAT == "json" { 
    $all_data | to json | save -f $provider_prices_path
  } else { 
    $all_data | to yaml | save -f $provider_prices_path
  }
  if $env.PROVISIONING_DEBUG {  print $"Storage prices for ($server.provider) in: ($provider_prices_path | path basename) with ($server.zone) saved" }
} 
export def aws_load_infra_servers [
  provider_prices_path: string
  settings: record
  server: record
] { 
  let curr_data = if ($provider_prices_path | path exists) { 
    (open $provider_prices_path)
  } else { 
    []
  }
  $curr_data | where {|it|
    if $it.zone? != null and $it.zone == $server.zone and $it.plan? != null and $it.plan == $server.plan { 
      return $curr_data
    }
  }
  let filter = { 
      field: "instanceType",
      value: $server.plan  
  }
  let data =  (aws_get_price_data $filter $server)
  let srv_data = { zone: $server.zone, plan: $server.plan, data: $data} 
  let all_data = if ($provider_prices_path | path exists) { 
    (open $provider_prices_path | append $srv_data)
  } else { 
    [$srv_data]
  }
  if $env.PROVISIONING_WK_FORMAT == "json" { 
    $all_data | to json | save -f $provider_prices_path
  } else { 
    $all_data | to yaml | save -f $provider_prices_path
  }
  if $env.PROVISIONING_DEBUG {  print $"Server prices for ($server.provider) in: ($provider_prices_path | path basename) with ($server.plan)/($server.zone) saved" }
  { plan: $server.plan, zone: $server.zone }
} 
