package main

import (
	"log"
	"strings"

	"github.com/shopspring/decimal"
)

var (
	instanceMarkup = decimal.New(23, -1)
	storageMarkup  = decimal.New(10, -1)
	// AWS io2 list price: see https://pingcap-cn.feishu.cn/wiki/AtdCwUzTKiQm4Qkyzd0cHTmWnLe
	io2IOPSMarkup = decimal.New(15, -1)
	hourPerMonth  = decimal.New(730, 0)
)

var instancePrice = map[string]map[string]map[string]string{ // by hour
	"aws": {
		// https://aws.amazon.com/ec2/pricing/on-demand/
		// x86
		"m5.large": {
			"us-east-1":      "0.096",
			"us-west-2":      "0.096",
			"ap-northeast-1": "0.124",
			"ap-southeast-1": "0.12",
			"eu-central-1":   "0.115",
			"ap-south-1":     "0.101",
			"ap-southeast-3": "0.12",
			"ap-northeast-2": "0.118",
			"ap-southeast-2": "0.12",
			"sa-east-1":      "0.15",
			"us-east-2":      "0.096",
			"ap-east-1":      "0.132",
		},
		"m5.xlarge": {
			"us-east-1":      "0.192",
			"us-west-2":      "0.192",
			"ap-northeast-1": "0.248",
			"ap-southeast-1": "0.24",
			"eu-central-1":   "0.23",
			"ap-south-1":     "0.202",
			"ap-southeast-3": "0.24",
			"ap-northeast-2": "0.236",
			"ap-southeast-2": "0.24",
			"sa-east-1":      "0.306",
			"us-east-2":      "0.192",
			"ap-east-1":      "0.264",
		},
		"m5.2xlarge": {
			"us-east-1":      "0.384",
			"us-west-2":      "0.384",
			"ap-northeast-1": "0.496",
			"ap-southeast-1": "0.48",
			"eu-central-1":   "0.46",
			"ap-south-1":     "0.404",
			"ap-southeast-3": "0.48",
			"ap-northeast-2": "0.472",
			"ap-southeast-2": "0.48",
			"sa-east-1":      "0.612",
			"us-east-2":      "0.384",
			"ap-east-1":      "0.528",
		},
		"m5.4xlarge": {
			"us-east-1":      "0.768",
			"us-west-2":      "0.768",
			"ap-northeast-1": "0.992",
			"ap-southeast-1": "0.96",
			"eu-central-1":   "0.92",
			"ap-south-1":     "0.808",
			"ap-southeast-3": "0.96",
			"ap-northeast-2": "0.944",
			"ap-southeast-2": "0.96",
			"sa-east-1":      "1.224",
			"us-east-2":      "0.768",
			"ap-east-1":      "1.056",
		},
		"m5.8xlarge": {
			"us-west-2":      "1.536",
			"sa-east-1":      "2.448",
			"us-east-1":      "1.536",
			"ap-northeast-1": "1.984",
			"ap-southeast-1": "1.92",
			"eu-central-1":   "1.84",
			"ap-northeast-2": "1.888",
			"ap-southeast-2": "1.92",
			"ap-south-1":     "1.616",
			"ap-southeast-3": "1.92",
			"us-east-2":      "1.536",
			"ap-east-1":      "2.112",
		},
		"c5.large": {
			"ap-northeast-2": "0.096",
			"ap-southeast-3": "0.098",
			"ap-southeast-2": "0.111",
			"us-east-1":      "0.085",
			"us-west-2":      "0.085",
			"ap-northeast-1": "0.107",
			"ap-southeast-1": "0.098",
			"eu-central-1":   "0.097",
			"ap-south-1":     "0.085",
			"sa-east-1":      "0.131",
			"us-east-2":      "0.085",
			"ap-east-1":      "0.108",
		},
		"c5.xlarge": {
			"ap-northeast-2": "0.192",
			"ap-southeast-3": "0.196",
			"ap-southeast-2": "0.222",
			"us-east-1":      "0.170",
			"us-west-2":      "0.170",
			"ap-northeast-1": "0.214",
			"ap-southeast-1": "0.196",
			"eu-central-1":   "0.194",
			"ap-south-1":     "0.17",
			"sa-east-1":      "0.262",
			"us-east-2":      "0.170",
			"ap-east-1":      "0.216",
		},
		"c5.2xlarge": {
			"ap-northeast-2": "0.384",
			"ap-southeast-3": "0.392",
			"ap-southeast-2": "0.444",
			"us-east-1":      "0.340",
			"us-west-2":      "0.340",
			"ap-northeast-1": "0.428",
			"ap-southeast-1": "0.392",
			"eu-central-1":   "0.388",
			"ap-south-1":     "0.34",
			"sa-east-1":      "0.524",
			"us-east-2":      "0.340",
			"ap-east-1":      "0.432",
		},
		"c5.4xlarge": {
			"ap-northeast-2": "0.768",
			"ap-southeast-3": "0.784",
			"ap-southeast-2": "0.888",
			"us-east-1":      "0.68",
			"us-west-2":      "0.68",
			"ap-northeast-1": "0.856",
			"ap-southeast-1": "0.784",
			"eu-central-1":   "0.776",
			"ap-south-1":     "0.68",
			"sa-east-1":      "1.048",
			"us-east-2":      "0.68",
			"ap-east-1":      "0.864",
		},
		"r5.2xlarge": {
			"us-east-1":      "0.504",
			"us-west-2":      "0.504",
			"ap-south-1":     "0.52",
			"ap-southeast-1": "0.608",
			"ap-southeast-3": "0.608",
			"ap-northeast-1": "0.608",
			"ap-northeast-2": "0.608",
			"eu-central-1":   "0.608",
			"ap-southeast-2": "0.604",
			"sa-east-1":      "0.804",
			"us-east-2":      "0.504",
			"ap-east-1":      "0.668",
		},
		"r5b.2xlarge": {
			"us-east-1":      "0.596",
			"us-west-2":      "0.596",
			"ap-northeast-1": "0.724",
			"ap-southeast-1": "0.712",
			"eu-central-1":   "0.712",
			"ap-northeast-2": "0.712",
			"ap-southeast-2": "0.724",
			"sa-east-1":      "0.948",
			"us-east-2":      "0.596",
		},
		"r5.4xlarge": {
			"us-east-1":      "1.008",
			"us-west-2":      "1.008",
			"ap-northeast-1": "1.216",
			"ap-southeast-1": "1.216",
			"eu-central-1":   "1.216",
			"ap-south-1":     "1.04",
			"ap-southeast-3": "1.216",
			"ap-northeast-2": "1.216",
			"ap-southeast-2": "1.208",
			"sa-east-1":      "1.608",
			"us-east-2":      "1.008",
			"ap-east-1":      "1.336",
		},
		"r5.8xlarge": {
			"us-east-1":      "2.016",
			"us-west-2":      "2.016",
			"ap-northeast-1": "2.432",
			"ap-southeast-1": "2.432",
			"eu-central-1":   "2.432",
			"ap-south-1":     "2.08",
			"ap-southeast-3": "2.432",
			"ap-northeast-2": "2.432",
			"ap-southeast-2": "2.416",
			"sa-east-1":      "3.216",
			"us-east-2":      "2.016",
			"ap-east-1":      "2.672",
		},
		"i3.2xlarge": {
			"ap-northeast-2": "0.732",
			"ap-southeast-3": "0.748",
			"us-west-2":      "0.624",
			"sa-east-1":      "0.996",
			"ap-south-1":     "0.708",
			"us-east-1":      "0.624",
			"ap-east-1":      "0.824",
		},
		"i3.4xlarge": {
			"ap-northeast-2": "1.464",
			"ap-southeast-3": "1.496",
			"sa-east-1":      "1.992",
			"ap-south-1":     "1.416",
			"us-west-2":      "1.248",
			"us-east-1":      "1.248",
			"us-east-2":      "1.248",
			"ap-east-1":      "1.648",
		},
		"t3a.medium": {
			"us-west-2":  "0.0376",
			"us-east-1":  "0.0336",
			"sa-east-1":  "0.0605",
			"ap-south-1": "0.0246",
		},
		"c6i.8xlarge": {
			"sa-east-1":      "2.096",
			"us-east-1":      "1.36",
			"us-west-2":      "1.36",
			"ap-northeast-1": "1.712",
			"ap-southeast-1": "1.568",
			"eu-central-1":   "1.552",
			"ap-northeast-2": "1.536",
			"ap-southeast-2": "1.776",
			"ap-south-1":     "1.36",
			"us-east-2":      "1.36",
			"ap-east-1":      "1.728",
		},
		"r6i.8xlarge": {
			"sa-east-1":      "3.216",
			"us-east-1":      "2.016",
			"us-west-2":      "2.016",
			"ap-northeast-1": "2.432",
			"ap-southeast-1": "2.432",
			"eu-central-1":   "2.432",
			"ap-northeast-2": "2.432",
			"ap-southeast-2": "2.416",
			"ap-south-1":     "2.08",
			"us-east-2":      "2.016",
			"ap-east-1":      "2.672",
		},
		"m6i.8xlarge": {
			"sa-east-1":      "2.448",
			"us-east-1":      "1.536",
			"us-west-2":      "1.536",
			"ap-northeast-1": "1.984",
			"ap-southeast-1": "1.92",
			"eu-central-1":   "1.84",
			"ap-northeast-2": "1.888",
			"ap-southeast-2": "1.92",
			"ap-south-1":     "1.616",
			"ap-southeast-3": "1.92",
			"us-east-2":      "1.536",
			"ap-east-1":      "2.112",
		},
		"m6i.16xlarge": {
			"us-west-2":      "3.072",
			"us-east-1":      "3.072",
			"ap-southeast-1": "3.84",
		},

		// ARM
		// use the `armInstancePriceMapping` to configure prices for arm instances
		/*
			"t4g.medium": {
				"us-west-2": "0.0336",
				"us-east-1": "0.0336",
			},
			"m6g.large": {
				"us-east-1": "0.096", "us-west-2": "0.096", "ap-northeast-1": "0.124", "ap-northeast-2": "0.094", "ap-southeast-1": "0.12", "eu-central-1": "0.115", "ap-south-1": "0.101",
				"ap-southeast-3": "0.096",
			},
			"m6g.xlarge": {
				"us-east-1": "0.192", "us-west-2": "0.192", "ap-northeast-1": "0.248", "ap-northeast-2": "0.188", "ap-southeast-1": "0.24", "eu-central-1": "0.23", "ap-south-1": "0.202",
				"ap-southeast-3": "0.192",
			},
			"m6g.2xlarge": {
				"us-east-1": "0.384", "us-west-2": "0.384", "ap-northeast-1": "0.496", "ap-northeast-2": "0.376", "ap-southeast-1": "0.48", "eu-central-1": "0.46", "ap-south-1": "0.404",
				"ap-southeast-3": "0.384",
			},
			"m6g.4xlarge": {
				"us-east-1": "0.768", "us-west-2": "0.768", "ap-northeast-1": "0.992", "ap-northeast-2": "0.752", "ap-southeast-1": "0.96", "eu-central-1": "0.92", "ap-south-1": "0.808",
				"ap-southeast-3": "0.768",
			},
			"c6g.xlarge": {
				"ap-northeast-2": "0.192",
				"ap-southeast-3": "0.1568",

				"us-east-1": "0.170", "us-west-2": "0.170", "ap-northeast-1": "0.214", "ap-southeast-1": "0.196", "eu-central-1": "0.194", "ap-south-1": "0.17",
			},
			"c6g.2xlarge": {
				"ap-northeast-2": "0.384",
				"ap-southeast-3": "0.3136",

				"us-east-1": "0.340", "us-west-2": "0.340", "ap-northeast-1": "0.428", "ap-southeast-1": "0.392", "eu-central-1": "0.388", "ap-south-1": "0.34",
			},
			"c6g.4xlarge": {
				"ap-northeast-2": "0.768",
				"ap-southeast-3": "0.6272",
				"us-east-1":      "0.68", "us-west-2": "0.68", "ap-northeast-1": "0.856", "ap-southeast-1": "0.784", "eu-central-1": "0.776", "ap-south-1": "0.68",
			},
			"r6g.2xlarge": {
				"us-east-1": "0.596", "us-west-2": "0.596", "ap-northeast-1": "0.724", "ap-northeast-2": "0.488", "ap-southeast-1": "0.712", "eu-central-1": "0.712", "ap-south-1": "0.52",
				"ap-southeast-3": "0.4864",
			},
			"r6g.4xlarge": {
				"us-east-1": "1.008", "us-west-2": "1.008", "ap-northeast-1": "1.216", "ap-northeast-2": "0.976", "ap-southeast-1": "1.216", "eu-central-1": "1.216", "ap-south-1": "1.04",
				"ap-southeast-3": "0.9728",
			},
		*/
		"aws_freetier_10": {
			"us-east-1":      "0",
			"us-west-2":      "0",
			"ap-northeast-1": "0",
			"ap-southeast-1": "0",
			"eu-central-1":   "0",
		},
	},
	"gcp": {
		// https://cloud.google.com/compute/vm-instance-pricing, the price is per hour
		// for custom instance type, search for "N2 custom vCPUs and memory"
		"n1-standard-2": {
			"us-central1":     "0.0949995",
			"us-west1":        "0.0949995",
			"asia-northeast1": "0.122",
			"asia-southeast1": "0.1172",
			"asia-east1":      "0.1100",
			"asia-northeast2": "0.1220",
			"us-east4":        "0.1070",
			"us-west2":        "0.1142",
			"asia-southeast2": "0.1172",
			"asia-east2":      "0.1329",
		},
		"n1-standard-4": {
			"us-central1":     "0.189999",
			"us-west1":        "0.189999",
			"asia-northeast1": "0.2440",
			"asia-southeast1": "0.2344",
			"asia-east1":      "0.2200",
			"asia-northeast2": "0.2440",
			"us-east4":        "0.2140",
			"us-west2":        "0.2284",
			"asia-southeast2": "0.2344",
			"asia-east2":      "0.2658",
		},
		"n2-standard-2": {
			"us-central1":     "0.097118",
			"us-west1":        "0.097118",
			"asia-northeast1": "0.124588",
			"asia-southeast1": "0.119806",
			"asia-east1":      "0.112452",
			"asia-northeast2": "0.124588",
			"us-east4":        "0.109378",
			"us-west2":        "0.116652",
			"asia-southeast2": "0.130586",
			"asia-east2":      "0.135886",
		},
		"n2-standard-4": {
			"us-central1":     "0.194236",
			"us-west1":        "0.194236",
			"asia-northeast1": "0.249176",
			"asia-southeast1": "0.239612",
			"asia-east1":      "0.224904",
			"asia-northeast2": "0.249176",
			"us-east4":        "0.218756",
			"us-west2":        "0.233304",
			"asia-southeast2": "0.261172",
			"asia-east2":      "0.271772",
		},
		"n2-standard-8": {
			"us-central1":     "0.388472",
			"us-west1":        "0.388472",
			"asia-northeast1": "0.498352",
			"asia-southeast1": "0.479224",
			"asia-east1":      "0.449808",
			"asia-northeast2": "0.498352",
			"us-east4":        "0.437512",
			"us-west2":        "0.466608",
			"asia-southeast2": "0.522344",
			"asia-east2":      "0.543544",
		},
		"n2-custom-8-16384": {
			"us-central1":     "0.33672",
			"us-east4":        "0.37924",
			"us-west1":        "0.33672",
			"asia-northeast2": "0.432408",
			"asia-southeast1": "0.415384",
			"asia-southeast2": "0.452768",
			"asia-east1":      "0.389872",
			"us-west2":        "0.40444",
			"asia-northeast1": "0.432232",
			"asia-east2":      "0.471128",
		},
		"n2-standard-16": {
			"us-central1":     "0.776944",
			"us-west1":        "0.776944",
			"asia-northeast1": "0.996704",
			"asia-southeast1": "0.958448",
			"asia-east1":      "0.899616",
			"asia-northeast2": "0.996704",
			"us-east4":        "0.875024",
			"asia-southeast2": "1.044688",
			"asia-east2":      "1.087088",
		},
		"t2d-standard-16": {
			"us-central1":     "0.776944",
			"us-west1":        "0.776944",
			"asia-northeast1": "0.996704",
			"asia-southeast1": "0.958448",
			"asia-east1":      "0.899616",
			"asia-northeast2": "0.996704",
			"us-east4":        "0.875024",
			"asia-east2":      "1.087088",
		},
		"n2-custom-16-32768": {
			"us-central1":     "0.67344",
			"us-west1":        "0.67344",
			"asia-northeast1": "0.864464",
			"asia-southeast1": "0.830768",
			"asia-east1":      "0.779744",
			"asia-northeast2": "0.864816",
			"us-east4":        "0.75848",
			"asia-southeast2": "0.905536",
			"asia-east2":      "0.942256",
		},
		"n2-highmem-8": {
			"us-central1":     "0.524056",
			"us-west1":        "0.524056",
			"asia-northeast1": "0.67176",
			"asia-southeast1": "0.646456",
			"asia-east1":      "0.6068",
			"asia-northeast2": "0.67176",
			"us-east4":        "0.590184",
			"us-west2":        "0.629456",
			"asia-southeast2": "0.704616",
			"asia-east2":      "0.73324",
		},
		"n2-highmem-16": {
			"us-central1":     "1.048112",
			"us-west1":        "1.048112",
			"asia-northeast1": "1.34352",
			"asia-southeast1": "1.292912",
			"asia-east1":      "1.2136",
			"asia-northeast2": "1.34352",
			"us-east4":        "1.180368",
			"asia-southeast2": "1.409232",
			"asia-east2":      "1.46648",
		},
		"n1-standard-1": {
			//"asia-northeast1": "0.0610",
			// hacked the price of n1-standard-1, see https://pingcap.feishu.cn/docs/doccntfZhEgQFI0BSsH5NBXysBW
			"asia-northeast1": "0.0309",
			"us-west1":        "0.0309",
		},
		"e2-medium": {
			"us-west1": "0.033503",
			"us-west2": "0.040243",
			"us-east1": "0.033503",
		},
		"n2-standard-32": {
			// https://pingcap.feishu.cn/wiki/CWFawXQVjiGFvJk82hucYoHbnof
			"asia-east2":      "2.174176",
			"asia-southeast2": "2.089376",
			"asia-east1":      "1.799232",
			"asia-northeast1": "1.993408",
			"us-west1":        "1.553888",
			"us-east4":        "1.750048",
			"us-central1":     "1.553888",
			"asia-southeast1": "1.916896",
		},
	},
}

type armInstancePriceBuilder struct {
	X86InstanceType string
	Factor          int64
}

// armInstancePriceMapping defines a mapping to map arm instance to arm instance price builder.
// The price of arm instance is calculated by the price of x86 instance * factor.
var armInstancePriceMapping = map[string]armInstancePriceBuilder{
	"t4g.medium": {
		"t3a.medium",
		1,
	},
	"m6g.large": {
		"m5.large",
		1,
	},
	"m6g.xlarge": {
		"m5.xlarge",
		1,
	},
	"m6g.2xlarge": {
		"m5.2xlarge",
		1,
	},
	"m6g.4xlarge": {
		"m5.4xlarge",
		1,
	},
	"c6g.large": {
		"c5.large",
		1,
	},
	"c6g.xlarge": {
		"c5.xlarge",
		1,
	},
	"c6g.2xlarge": {
		"c5.2xlarge",
		1,
	},
	"c6g.4xlarge": {
		"c5.4xlarge",
		1,
	},
	"r6g.2xlarge": {
		"r5.2xlarge",
		1,
	},
	"r6g.4xlarge": {
		"r5.4xlarge",
		1,
	},
	"c6g.8xlarge": {
		"c5.4xlarge",
		2,
	},
	"c6g.16xlarge": {
		"c5.4xlarge",
		4,
	},
	"m6g.8xlarge": {
		"m5.8xlarge",
		1,
	},
	"r6g.8xlarge": {
		"r5.8xlarge",
		1,
	},
	"m6g.16xlarge": {
		"m6i.16xlarge",
		1,
	},
}

var diskStoragePrice = map[string]map[string]map[string]string{ // by month
	"aws": {
		// https://aws.amazon.com/ebs/pricing/
		"gp3": {
			"ap-northeast-2": "0.0912",
			"ap-southeast-3": "0.096",
			"ap-southeast-2": "0.096",
			"us-east-1":      "0.08",
			"us-west-2":      "0.08",
			"ap-northeast-1": "0.096",
			"ap-southeast-1": "0.096",
			"eu-central-1":   "0.0952",
			"ap-south-1":     "0.0912",
			"sa-east-1":      "0.152",
			"us-east-2":      "0.08",
			"ap-east-1":      "0.1056",
		},
		"io2": {
			"us-west-2":      "0.125",
			"ap-northeast-2": "0.1278",
			"ap-southeast-2": "0.138",
			"us-east-1":      "0.125",
			"ap-northeast-1": "0.142",
			"ap-southeast-1": "0.138",
			"eu-central-1":   "0.149",
			"ap-south-1":     "0.131",
			"sa-east-1":      "0.238",
			"us-east-2":      "0.125",
			"ap-east-1":      "0.1518",
		},
		"aws_freetier_10": {
			"us-east-1":      "0",
			"us-west-2":      "0",
			"ap-northeast-1": "0",
			"ap-southeast-1": "0",
			"eu-central-1":   "0",
		},
		"local-storage": {
			"ap-southeast-3": "0",
			"ap-northeast-2": "0",
			"ap-southeast-2": "0",
			"us-east-1":      "0",
			"us-west-2":      "0",
			"ap-northeast-1": "0",
			"ap-southeast-1": "0",
			"eu-central-1":   "0",
			"ap-south-1":     "0",
			"sa-east-1":      "0",
			"us-east-2":      "0",
			"ap-east-1":      "0",
		},
		"gp2": {
			"ap-northeast-2": "0.1278",
			"ap-southeast-3": "0.12",
			"ap-southeast-2": "0.12",
			"us-west-2":      "0.10",
			"sa-east-1":      "0.19",
			"ap-south-1":     "0.114",
			"us-east-1":      "0.10",
			"ap-east-1":      "0.132",
		},
	},
	// https://cloud.google.com/compute/disks-image-pricing#disk
	"gcp": {
		"pd-ssd": {
			"us-central1":     "0.17",
			"us-west1":        "0.17",
			"asia-northeast1": "0.221",
			"asia-southeast1": "0.187",
			"asia-southeast2": "0.221",
			"asia-east1":      "0.170",
			"asia-northeast2": "0.221",
			"us-east4":        "0.187",
			"us-west2":        "0.204",
			"asia-east2":      "0.187",
		},
		"local-storage": {
			"us-central1":     "0.08",
			"us-west1":        "0.08",
			"asia-northeast1": "0.104",
			"asia-southeast1": "0.088",
			"asia-southeast2": "0.0959",
			"asia-east1":      "0.080",
			"asia-northeast2": "0.104",
			"us-east4":        "0.088",
			"us-west2":        "0.096",
			"asia-east2":      "0.112",
		},
	},
}

var diskIOPSPrice = map[string]map[string]map[string]string{ // by month
	"aws": {
		"gp3": {
			"ap-northeast-2": "0.0057",
			"ap-southeast-3": "0.006",
			"ap-southeast-2": "0.006",
			"us-east-1":      "0.005",
			"us-west-2":      "0.005",
			"ap-northeast-1": "0.006",
			"ap-southeast-1": "0.006",
			"eu-central-1":   "0.006",
			"ap-south-1":     "0.0057",
			"sa-east-1":      "0.0095",
			"us-east-2":      "0.005",
			"ap-east-1":      "0.0066",
		},
		"io2": {
			"us-west-2":      "0.065",
			"ap-northeast-2": "0.067",
			"ap-southeast-2": "0.072",
			"us-east-1":      "0.065",
			"ap-northeast-1": "0.074",
			"ap-southeast-1": "0.072",
			"eu-central-1":   "0.078",
			"ap-south-1":     "0.068",
			"sa-east-1":      "0.091", // sa-east-1 region does not support io2, update the price if supported in the future
			"us-east-2":      "0.065",
			"ap-east-1":      "0.079",
		},
		"aws_freetier_10": {
			"us-east-1":      "0",
			"us-west-2":      "0",
			"ap-northeast-1": "0",
			"ap-southeast-1": "0",
			"eu-central-1":   "0",
		},
	},
}

var diskThroughputPrice = map[string]map[string]map[string]string{ // by month
	"aws": {
		"gp3": {
			"ap-northeast-2": "0.0456",
			"ap-southeast-3": "0.048",
			"ap-southeast-2": "0.048",
			"us-east-1":      "0.04",
			"us-west-2":      "0.04",
			"ap-northeast-1": "0.048",
			"ap-southeast-1": "0.048",
			"eu-central-1":   "0.0476",
			"ap-south-1":     "0.046",
			"sa-east-1":      "0.076",
			"us-east-2":      "0.04",
			"ap-east-1":      "0.053",
		},
		"io2": {
			"us-west-2":      "0.0",
			"ap-northeast-2": "0.0",
			"ap-southeast-3": "0.0",
			"ap-southeast-2": "0.0",
			"us-east-1":      "0.0",
			"ap-northeast-1": "0.0",
			"ap-southeast-1": "0.0",
			"eu-central-1":   "0.0",
			"ap-south-1":     "0.0",
			"sa-east-1":      "0.0",
			"us-east-2":      "0.0",
			"ap-east-1":      "0.0",
		},
		"aws_freetier_10": {
			"us-east-1":      "0",
			"us-west-2":      "0",
			"ap-northeast-1": "0",
			"ap-southeast-1": "0",
			"eu-central-1":   "0",
		},
	},
}

func init() {
	awsPrices := instancePrice["aws"]

	for armInstance, item := range armInstancePriceMapping {
		regionPriceMapping := awsPrices[item.X86InstanceType]
		regionPriceMappingCopy := make(map[string]string, len(regionPriceMapping))
		for region, priceString := range regionPriceMapping {
			regionPriceMappingCopy[region] = priceString
		}

		for region, priceString := range regionPriceMappingCopy {
			price, err := decimal.NewFromString(priceString)
			if err != nil {
				panic(err)
			}

			factor := decimal.NewFromInt(item.Factor)
			newPriceString := price.Mul(factor).String()
			regionPriceMappingCopy[region] = newPriceString
		}

		awsPrices[armInstance] = regionPriceMappingCopy
	}
}

func getInstancePrice(provider string, region string, instanceType string) decimal.Decimal {
	// This hack is actually a bug. But we can't resolve it, since the price about this instance has been published
	// to our official website, and we can't arbitrary change the price.
	if strings.ToLower(provider) == "aws" &&
		(instanceType == "r5.2xlarge" || armInstancePriceMapping[instanceType].X86InstanceType == "r5.2xlarge") {
		// Note: newly enabled regions use r5b.2xlarge's price
		if region != "ap-east-1" && region != "ap-south-1" && region != "ap-southeast-3" && region != "ap-southeast-2" && region != "sa-east-1" {
			instanceType = "r5b.2xlarge"
		}
	}
	priceString, ok := instancePrice[strings.ToLower(provider)][instanceType][region]
	if !ok {
		panic("cannot find price for " + provider + " " + instanceType + " " + region)
	}
	price, err := decimal.NewFromString(priceString)
	if err != nil {
		panic(err)
	}
	return price.Mul(instanceMarkup).Truncate(4)
}

func getDiskStoragePrice(provider string, region string, diskType string) decimal.Decimal {
	priceString, ok := diskStoragePrice[strings.ToLower(provider)][diskType][region]
	if !ok {
		log.Fatalf("cannot find price for %s %s %s", provider, diskType, region)
	}

	price, err := decimal.NewFromString(priceString)
	if err != nil {
		panic(err)
	}
	return price.Div(hourPerMonth).Mul(storageMarkup).Truncate(6)
}

func getDiskIOPSPrice(provider string, region string, diskType string) decimal.Decimal {
	priceString, ok := diskIOPSPrice[strings.ToLower(provider)][diskType][region]
	if !ok {
		panic("cannot find price for " + provider + " " + diskType + " " + region)
	}

	price, err := decimal.NewFromString(priceString)
	if err != nil {
		panic(err)
	}

	if strings.ToLower(provider) == "aws" && diskType == "io2" {
		return price.Div(hourPerMonth).Mul(io2IOPSMarkup).Truncate(6)
	}

	return price.Div(hourPerMonth).Mul(storageMarkup).Truncate(6)
}

func getDiskThroughputPrice(provider string, region string, diskType string) decimal.Decimal {
	priceString, ok := diskThroughputPrice[strings.ToLower(provider)][diskType][region]
	if !ok {
		panic("cannot find price for " + provider + " " + diskType + " " + region)
	}

	price, err := decimal.NewFromString(priceString)
	if err != nil {
		panic(err)
	}
	return price.Div(hourPerMonth).Mul(storageMarkup).Truncate(6)
}
