/*
 * © 2021 Thoughtworks, Inc.
 */
import {
  CloudConstantsByProvider,
  CloudConstantsEmissionsFactors,
  COMPUTE_PROCESSOR_TYPES,
  EstimateUnknownUsageBy,
  getWattsByAverageOrMedian,
} from '@cloud-carbon-footprint/core'

import {
  GCP_DUAL_REGIONS,
  GCP_MULTI_REGIONS,
  GCP_REGIONS,
} from '../lib/GCPRegions'
import { configLoader } from '@cloud-carbon-footprint/common'

export const GCP_CLOUD_CONSTANTS: CloudConstantsByProvider = {
  SSDCOEFFICIENT: 1.2, // watt hours / terabyte hour
  HDDCOEFFICIENT: 0.65, // watt hours / terabyte hour
  MIN_WATTS_MEDIAN: 0.68,
  MIN_WATTS_BY_COMPUTE_PROCESSOR: {
    // CPUs
    [COMPUTE_PROCESSOR_TYPES.BROADWELL]: 0.71,
    [COMPUTE_PROCESSOR_TYPES.CASCADE_LAKE]: 0.69,
    [COMPUTE_PROCESSOR_TYPES.AMD_EPYC_3RD_GEN]: 0.46,
    [COMPUTE_PROCESSOR_TYPES.AMD_EPYC_4TH_GEN]: 0.74,
    [COMPUTE_PROCESSOR_TYPES.AMD_EPYC_5TH_GEN]: 0.27,
    [COMPUTE_PROCESSOR_TYPES.EMERALD_RAPIDS]: 0.81,
    [COMPUTE_PROCESSOR_TYPES.GRANITE_RAPIDS]: 0.58,
    [COMPUTE_PROCESSOR_TYPES.HASWELL]: 1.86,
    [COMPUTE_PROCESSOR_TYPES.ICELAKE]: 0.77,
    [COMPUTE_PROCESSOR_TYPES.IVY_BRIDGE]: 1.71,
    [COMPUTE_PROCESSOR_TYPES.SANDY_BRIDGE]: 2.21,
    [COMPUTE_PROCESSOR_TYPES.SAPPHIRE_RAPIDS]: 1.04,
    [COMPUTE_PROCESSOR_TYPES.SKYLAKE]: 0.61,
    // GPUs (GPUWatt Idle = min, GPUWatt 100% = max)
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_GB300]: 168,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_GB200]: 120,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_B200]: 120,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_H200]: 84,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_H100]: 84,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_A100]: 48,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_RTX_PRO_6000]: 72,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_L4]: 8.64,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_T4]: 8.4,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_V100]: 30,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_P100]: 30,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_P4]: 9,
  },
  getMinWatts: (computeProcessors: string[]): number => {
    const minWattsForProcessors: number[] = computeProcessors.map(
      (processor: string) => {
        return GCP_CLOUD_CONSTANTS.MIN_WATTS_BY_COMPUTE_PROCESSOR[processor]
      },
    )
    const wattsForProcessors: number = getWattsByAverageOrMedian(
      computeProcessors,
      minWattsForProcessors,
    )
    return wattsForProcessors
      ? wattsForProcessors
      : GCP_CLOUD_CONSTANTS.MIN_WATTS_MEDIAN
  },
  MAX_WATTS_MEDIAN: 4.11,
  MAX_WATTS_BY_COMPUTE_PROCESSOR: {
    // CPUs
    [COMPUTE_PROCESSOR_TYPES.BROADWELL]: 3.39,
    [COMPUTE_PROCESSOR_TYPES.CASCADE_LAKE]: 3.75,
    [COMPUTE_PROCESSOR_TYPES.AMD_EPYC_3RD_GEN]: 1.83,
    [COMPUTE_PROCESSOR_TYPES.AMD_EPYC_4TH_GEN]: 2.2,
    [COMPUTE_PROCESSOR_TYPES.AMD_EPYC_5TH_GEN]: 1.36,
    [COMPUTE_PROCESSOR_TYPES.EMERALD_RAPIDS]: 4.38,
    [COMPUTE_PROCESSOR_TYPES.GRANITE_RAPIDS]: 2.37,
    [COMPUTE_PROCESSOR_TYPES.HASWELL]: 5.56,
    [COMPUTE_PROCESSOR_TYPES.ICELAKE]: 3.65,
    [COMPUTE_PROCESSOR_TYPES.IVY_BRIDGE]: 5.51,
    [COMPUTE_PROCESSOR_TYPES.SANDY_BRIDGE]: 8.6,
    [COMPUTE_PROCESSOR_TYPES.SAPPHIRE_RAPIDS]: 4.06,
    [COMPUTE_PROCESSOR_TYPES.SKYLAKE]: 3.87,
    // GPUs (GPUWatt Idle = min, GPUWatt 100% = max)
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_GB300]: 1428,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_GB200]: 1020,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_B200]: 1020,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_H200]: 714,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_H100]: 714,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_A100]: 408,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_RTX_PRO_6000]: 612,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_L4]: 73.44,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_T4]: 71.4,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_V100]: 255,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_P100]: 255,
    [COMPUTE_PROCESSOR_TYPES.NVIDIA_TESLA_P4]: 76.5,
  },
  getMaxWatts: (computeProcessors: string[]): number => {
    const maxWattsForProcessors: number[] = computeProcessors.map(
      (processor: string) => {
        return GCP_CLOUD_CONSTANTS.MAX_WATTS_BY_COMPUTE_PROCESSOR[processor]
      },
    )
    const wattsForProcessors: number = getWattsByAverageOrMedian(
      computeProcessors,
      maxWattsForProcessors,
    )

    return wattsForProcessors
      ? wattsForProcessors
      : GCP_CLOUD_CONSTANTS.MAX_WATTS_MEDIAN
  },
  NETWORKING_COEFFICIENT: 0.001, // kWh / Gb
  MEMORY_COEFFICIENT: 0.000392, // kWh / Gb
  PUE_AVG: 1.1,
  PUE_TRAILING_TWELVE_MONTH: {
    [GCP_REGIONS.US_EAST4]: 1.08,
    [GCP_REGIONS.US_CENTRAL1]: 1.11,
    [GCP_REGIONS.US_CENTRAL2]: 1.11,
    [GCP_REGIONS.EUROPE_WEST1]: 1.09,
    [GCP_REGIONS.EUROPE_WEST4]: 1.07,
    [GCP_REGIONS.EUROPE_NORTH1]: 1.09,
    [GCP_REGIONS.ASIA_EAST1]: 1.12,
    [GCP_REGIONS.ASIA_SOUTHEAST1]: 1.13,
  },
  getPUE: (region: string): number => {
    // Return region-specific PUE if available, otherwise use fleet-wide average
    return GCP_CLOUD_CONSTANTS.PUE_TRAILING_TWELVE_MONTH[region]
      ? GCP_CLOUD_CONSTANTS.PUE_TRAILING_TWELVE_MONTH[region]
      : GCP_CLOUD_CONSTANTS.PUE_AVG
  },
  AVG_CPU_UTILIZATION_2020: 50,
  REPLICATION_FACTORS: {
    CLOUD_STORAGE_SINGLE_REGION: 2,
    CLOUD_STORAGE_DUAL_REGION: 2,
    CLOUD_STORAGE_MULTI_REGION: 2,
    COMPUTE_ENGINE_REGIONAL_DISKS: 2,
    CLOUD_FILESTORE: 2,
    CLOUD_SQL_HIGH_AVAILABILITY: 2,
    CLOUD_MEMORY_STORE_REDIS: 2,
    CLOUD_SPANNER_SINGLE_REGION: 2,
    CLOUD_SPANNER_MULTI_REGION: 2,
    KUBERNETES_ENGINE: 3,
    DEFAULT: 1,
  },
  // these constants accumulate as the usage rows are mapped over
  KILOWATT_HOURS_BY_SERVICE_AND_USAGE_UNIT: {
    total: {},
  },
  ESTIMATE_UNKNOWN_USAGE_BY: EstimateUnknownUsageBy.USAGE_AMOUNT,
  SERVER_EXPECTED_LIFESPAN: 35040, // 4 years in hours
}

export const getGCPEmissionsFactors = (): CloudConstantsEmissionsFactors => {
  // These emission factors take into account Google Carbon Free Energy percentage in each region. Source: https://cloud.google.com/sustainability/region-carbon
  if (configLoader().GCP.USE_CARBON_FREE_ENERGY_PERCENTAGE)
    return {
      [GCP_REGIONS.US_CENTRAL1]: 0.0000537,
      [GCP_REGIONS.US_CENTRAL2]: 0.0000446,
      [GCP_REGIONS.US_EAST1]: 0.0003974,
      [GCP_REGIONS.US_EAST4]: 0.0001227,
      [GCP_REGIONS.US_EAST5]: 0.0001227,
      [GCP_REGIONS.US_WEST1]: 0.0000103,
      [GCP_REGIONS.US_WEST2]: 0.0000625,
      [GCP_REGIONS.US_WEST3]: 0.0003719,
      [GCP_REGIONS.US_WEST4]: 0.0001285,
      [GCP_REGIONS.US_SOUTH1]: 0.0000182,
      [GCP_REGIONS.ASIA_EAST1]: 0.0003644,
      [GCP_REGIONS.ASIA_EAST2]: 0.0005,
      [GCP_REGIONS.ASIA_NORTHEAST1]: 0.000376,
      [GCP_REGIONS.ASIA_NORTHEAST2]: 0.0001598,
      [GCP_REGIONS.ASIA_NORTHEAST3]: 0.0002249,
      [GCP_REGIONS.ASIA_SOUTH1]: 0.0006179,
      [GCP_REGIONS.ASIA_SOUTH2]: 0.0003777,
      [GCP_REGIONS.ASIA_SOUTHEAST1]: 0.0003523,
      [GCP_REGIONS.ASIA_SOUTHEAST2]: 0.00046,
      [GCP_REGIONS.AUSTRALIA_SOUTHEAST1]: 0.0003287,
      [GCP_REGIONS.AUSTRALIA_SOUTHEAST2]: 0.0002769,
      [GCP_REGIONS.EUROPE_CENTRAL2]: 0.0003858,
      [GCP_REGIONS.EUROPE_NORTH1]: 0.0000008,
      [GCP_REGIONS.EUROPE_SOUTHWEST1]: 0.0000116,
      [GCP_REGIONS.EUROPE_WEST1]: 0.0000165,
      [GCP_REGIONS.EUROPE_WEST2]: 0.0000223,
      [GCP_REGIONS.EUROPE_WEST3]: 0.0000883,
      [GCP_REGIONS.EUROPE_WEST4]: 0.0000355,
      [GCP_REGIONS.EUROPE_WEST6]: 0.0000003,
      [GCP_REGIONS.EUROPE_WEST8]: 0.0000545,
      [GCP_REGIONS.EUROPE_WEST9]: 0.0000006,
      [GCP_REGIONS.EUROPE_WEST10]: 0.0000883,
      [GCP_REGIONS.EUROPE_WEST12]: 0.0000545,
      [GCP_REGIONS.NORTHAMERICA_NORTHEAST1]: 0.0000001, // Montreal is 100% CFE
      [GCP_REGIONS.NORTHAMERICA_NORTHEAST2]: 0.0000094,
      [GCP_REGIONS.SOUTHAMERICA_EAST1]: 0.000008,
      [GCP_REGIONS.SOUTHAMERICA_WEST1]: 0.000019,
      [GCP_REGIONS.AFRICA_SOUTH1]: 0.0005585,
      [GCP_REGIONS.EUROPE_NORTH2]: 0,
      [GCP_REGIONS.MIDDLEEAST_CENTRAL1]: 0.0003623,
      [GCP_REGIONS.MIDDLEEAST_CENTRAL2]: 0.0003782,
      [GCP_REGIONS.MIDDLEEAST_WEST1]: 0.0004036,
      [GCP_REGIONS.NORTHAMERICA_SOUTH1]: 0.0002471,
      [GCP_REGIONS.US_EAST2]: 0.0001972,
      [GCP_DUAL_REGIONS.ASIA1]: 0.0005358, // Sum of asia-northeast1 + asia-northeast2
      [GCP_DUAL_REGIONS.EUR4]: 0.0000363, // Sum of europe-west4 + europe-north1
      [GCP_DUAL_REGIONS.NAM4]: 0.0004511, // Sum of us-central1 + us-east1
      [GCP_MULTI_REGIONS.ASIA]: 0.002473, // Sum of region group data centers within Asia
      [GCP_MULTI_REGIONS.EU]: 0.0007364, // Sum of EU region data centers (BE, FI, SE, ES, DE, NL, IT, FR, PL)
      [GCP_MULTI_REGIONS.US]: 0.0015297, // Sum of all US data centers
      [GCP_REGIONS.UNKNOWN]: 0.0001889431818, // Average across all regions (excluding multi and dual regions)
    }
  // These emissions factors don't take into account Google's CFE%, and just use the Grid emissions factors published by Google.
  return {
    [GCP_REGIONS.US_CENTRAL1]: 0.000413,
    [GCP_REGIONS.US_CENTRAL2]: 0.000372,
    [GCP_REGIONS.US_EAST1]: 0.000576,
    [GCP_REGIONS.US_EAST4]: 0.000323,
    [GCP_REGIONS.US_EAST5]: 0.000323,
    [GCP_REGIONS.US_WEST1]: 0.000079,
    [GCP_REGIONS.US_WEST2]: 0.000169,
    [GCP_REGIONS.US_WEST3]: 0.000555,
    [GCP_REGIONS.US_WEST4]: 0.000357,
    [GCP_REGIONS.US_SOUTH1]: 0.000303,
    [GCP_REGIONS.ASIA_EAST1]: 0.000439,
    [GCP_REGIONS.ASIA_EAST2]: 0.000505,
    [GCP_REGIONS.ASIA_NORTHEAST1]: 0.000453,
    [GCP_REGIONS.ASIA_NORTHEAST2]: 0.000296,
    [GCP_REGIONS.ASIA_NORTHEAST3]: 0.000357,
    [GCP_REGIONS.ASIA_SOUTH1]: 0.000679,
    [GCP_REGIONS.ASIA_SOUTH2]: 0.000532,
    [GCP_REGIONS.ASIA_SOUTHEAST1]: 0.000367,
    [GCP_REGIONS.ASIA_SOUTHEAST2]: 0.000561,
    [GCP_REGIONS.AUSTRALIA_SOUTHEAST1]: 0.000498,
    [GCP_REGIONS.AUSTRALIA_SOUTHEAST2]: 0.000454,
    [GCP_REGIONS.EUROPE_CENTRAL2]: 0.000643,
    [GCP_REGIONS.EUROPE_NORTH1]: 0.000039,
    [GCP_REGIONS.EUROPE_SOUTHWEST1]: 0.000089,
    [GCP_REGIONS.EUROPE_WEST1]: 0.000103,
    [GCP_REGIONS.EUROPE_WEST2]: 0.000106,
    [GCP_REGIONS.EUROPE_WEST3]: 0.000276,
    [GCP_REGIONS.EUROPE_WEST4]: 0.000209,
    [GCP_REGIONS.EUROPE_WEST6]: 0.000015,
    [GCP_REGIONS.EUROPE_WEST8]: 0.000202,
    [GCP_REGIONS.EUROPE_WEST9]: 0.000016,
    [GCP_REGIONS.EUROPE_WEST10]: 0.000276,
    [GCP_REGIONS.EUROPE_WEST12]: 0.000202,
    [GCP_REGIONS.NORTHAMERICA_NORTHEAST1]: 0.000005,
    [GCP_REGIONS.NORTHAMERICA_NORTHEAST2]: 0.000059,
    [GCP_REGIONS.SOUTHAMERICA_EAST1]: 0.000067,
    [GCP_REGIONS.SOUTHAMERICA_WEST1]: 0.000238,
    [GCP_REGIONS.AFRICA_SOUTH1]: 0.000657,
    [GCP_REGIONS.EUROPE_NORTH2]: 0.000003,
    [GCP_REGIONS.MIDDLEEAST_CENTRAL1]: 0.000366,
    [GCP_REGIONS.MIDDLEEAST_CENTRAL2]: 0.000382,
    [GCP_REGIONS.MIDDLEEAST_WEST1]: 0.000434,
    [GCP_REGIONS.NORTHAMERICA_SOUTH1]: 0.000305,
    [GCP_REGIONS.US_EAST2]: 0.00034,
    [GCP_DUAL_REGIONS.ASIA1]: 0.000749, // Sum of asia-northeast1 + asia-northeast2
    [GCP_DUAL_REGIONS.EUR4]: 0.000248, // Sum of europe-west4 + europe-north1
    [GCP_DUAL_REGIONS.NAM4]: 0.000989, // Sum of us-central1 + us-east1
    [GCP_MULTI_REGIONS.ASIA]: 0.003123, // Sum of region group data centers within Asia
    [GCP_MULTI_REGIONS.EU]: 0.002058, // Sum of EU region data centers (BE, FI, SE, ES, DE, NL, IT, FR, PL)
    [GCP_MULTI_REGIONS.US]: 0.00381, // Sum of all US data centers
    [GCP_REGIONS.UNKNOWN]: 0.0003100681818, // Average of the above regions (excludes multi/dual-regions)
  }
}
