package utils

import (
	"regexp"
	"slices"
	"strconv"
	"strings"
	"time"

	"github.com/juju/errors"
)

var NAME_PATTERN = regexp.MustCompile(`\(.*\)`)
var AREA_PATTERN = regexp.MustCompile(`[\(]`)

type AwsRegion struct {
	FullName string
	Name     string
	Country  string
	Area     string
	TimeZone string
}

var AwsRegions = []AwsRegion{
	{FullName: "US East (Ohio)", Name: "us-east-2", Country: "US", Area: "North America", TimeZone: "UTC-4"},
	{FullName: "US East (N. Virginia)", Name: "us-east-1", Country: "US", Area: "North America", TimeZone: "UTC-4"},
	{FullName: "US West (N. California)", Name: "us-west-1", Country: "US", Area: "North America", TimeZone: "UTC-7"},
	{FullName: "US West (Oregon)", Name: "us-west-2", Country: "US", Area: "North America", TimeZone: "UTC-7"},
	{FullName: "Africa (Cape Town)", Name: "af-south-1", Country: "ZA", Area: "Africa", TimeZone: "UTC+2"},
	{FullName: "Asia Pacific (Hong Kong)", Name: "ap-east-1", Country: "CN", Area: "Asia Pacific", TimeZone: "UTC+8"},
	{FullName: "Asia Pacific (Hyderabad)", Name: "ap-south-2", Country: "IN", Area: "Asia Pacific", TimeZone: "UTC+5:30"},
	{FullName: "Asia Pacific (Jakarta)", Name: "ap-southeast-3", Country: "ID", Area: "Asia Pacific", TimeZone: "UTC+7"},
	{FullName: "Asia Pacific (Melbourne)", Name: "ap-southeast-4", Country: "AU", Area: "Asia Pacific", TimeZone: "UTC+10"},
	{FullName: "Asia Pacific (Malaysia)", Name: "ap-southeast-5", Country: "MY", Area: "Asia Pacific", TimeZone: "UTC+8"},
	{FullName: "Asia Pacific (New Zealand)", Name: "ap-southeast-6", Country: "NZ", Area: "Asia Pacific", TimeZone: "UTC+13"},
	{FullName: "Asia Pacific (Thailand)", Name: "ap-southeast-7", Country: "TH", Area: "Asia Pacific", TimeZone: "UTC+7"},
	{FullName: "Asia Pacific (Mumbai)", Name: "ap-south-1", Country: "IN", Area: "Asia Pacific", TimeZone: "UTC+5:30"},
	{FullName: "Asia Pacific (Osaka)", Name: "ap-northeast-3", Country: "JP", Area: "Asia Pacific", TimeZone: "UTC+9"},
	{FullName: "Asia Pacific (Seoul)", Name: "ap-northeast-2", Country: "KR", Area: "Asia Pacific", TimeZone: "UTC+9"},
	{FullName: "Asia Pacific (Singapore)", Name: "ap-southeast-1", Country: "SG", Area: "Asia Pacific", TimeZone: "UTC+8"},
	{FullName: "Asia Pacific (Sydney)", Name: "ap-southeast-2", Country: "AU", Area: "Asia Pacific", TimeZone: "UTC+10"},
	{FullName: "Asia Pacific (Tokyo)", Name: "ap-northeast-1", Country: "JP", Area: "Asia Pacific", TimeZone: "UTC+9"},
	{FullName: "Canada (Central)", Name: "ca-central-1", Country: "CA", Area: "North America", TimeZone: "UTC-6"},
	{FullName: "Canada West (Calgary)", Name: "ca-west-1", Country: "CA", Area: "North America", TimeZone: "UTC-6"},
	{FullName: "China (Beijing)", Name: "cn-north-1", Country: "CN", Area: "China", TimeZone: "UTC+8"},
	{FullName: "China (Ningxia)", Name: "cn-northwest-1", Country: "CN", Area: "China", TimeZone: "UTC+8"},
	{FullName: "Europe (Frankfurt)", Name: "eu-central-1", Country: "DE", Area: "Europe", TimeZone: "UTC+2"},
	{FullName: "Europe (Ireland)", Name: "eu-west-1", Country: "IE", Area: "Europe", TimeZone: "UTC+1"},
	{FullName: "Europe (London)", Name: "eu-west-2", Country: "GB", Area: "Europe", TimeZone: "UTC+1"},
	{FullName: "Europe (Milan)", Name: "eu-south-1", Country: "IT", Area: "Europe", TimeZone: "UTC+2"},
	{FullName: "Europe (Paris)", Name: "eu-west-3", Country: "FR", Area: "Europe", TimeZone: "UTC+2"},
	{FullName: "Europe (Spain)", Name: "eu-south-2", Country: "ES", Area: "Europe", TimeZone: "UTC+1"},
	{FullName: "Europe (Stockholm)", Name: "eu-north-1", Country: "SE", Area: "Europe", TimeZone: "UTC+2"},
	{FullName: "Europe (Zurich)", Name: "eu-central-2", Country: "CH", Area: "Europe", TimeZone: "UTC+2"},
	{FullName: "Israel (Tel Aviv)", Name: "il-central-1", Country: "IL", Area: "Middle East", TimeZone: "UTC+3"},
	{FullName: "Middle East (Bahrain)", Name: "me-south-1", Country: "BH", Area: "Middle East", TimeZone: "UTC+3"},
	{FullName: "Middle East (UAE)", Name: "me-central-1", Country: "AE", Area: "Middle East", TimeZone: "UTC+4"},
	{FullName: "South America (São Paulo)", Name: "sa-east-1", Country: "BR", Area: "South America", TimeZone: "UTC-3"},
	{FullName: "AWS GovCloud (US-East)", Name: "us-gov-east-1", Country: "US", Area: "North America", TimeZone: "UTC-7"},
	{FullName: "AWS GovCloud (US-West)", Name: "us-gov-west-1", Country: "US", Area: "North America", TimeZone: "UTC-7"},
}

func GetAwsRegionName(region string) (string, error) {
	index := slices.IndexFunc(AwsRegions, func(e AwsRegion) bool {
		return e.Name == region

	})
	if index < 0 {
		return "", errors.NotFoundf("Region not found. Please see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html and add a new region")
	}

	fullName := AwsRegions[index].FullName
	name := string(NAME_PATTERN.Find([]byte(fullName)))
	return strings.Trim(name, "()"), nil
}

func GetAwsRegionCountryCode(region string) (string, error) {
	index := slices.IndexFunc(AwsRegions, func(e AwsRegion) bool {
		return e.Name == region

	})
	if index < 0 {
		return "", errors.NotFoundf("Region not found. Please see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html and add a new region")
	}

	return AwsRegions[index].Country, nil
}

func GetAwsRegionArea(region string) (string, error) {
	index := slices.IndexFunc(AwsRegions, func(e AwsRegion) bool {
		return e.Name == region

	})
	if index < 0 {
		return "", errors.NotFoundf("Region not found. Please see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html and add a new region")
	}

	return AwsRegions[index].Area, nil
}

func GetAwsRegionBackupTime(region string) (string, error) {
	index := slices.IndexFunc(AwsRegions, func(e AwsRegion) bool {
		return e.Name == region

	})
	if index < 0 {
		return "", errors.NotFoundf("Region not found. Please see https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html and add a new region")
	}
	return GetBackupTimeByTimeZone(AwsRegions[index].TimeZone)
}

func GetBackupTimeByTimeZone(timezone string) (string, error) {
	offset, err := ParseUtcTimeZoneOffset(timezone)
	if err != nil {
		return "", err
	}

	t, err := time.ParseInLocation("15:04", "02:00", time.FixedZone(timezone, offset))
	if err != nil {
		return "", err
	}
	*t.Location() = *time.UTC
	return t.Format("15:04"), nil
}

func ParseUtcTimeZoneOffset(timezone string) (int, error) {
	t := timezone
	if strings.HasPrefix(strings.ToUpper(t), "UTC") {
		t = t[3:] // remove prefix
	}
	if len(t) == 0 {
		return 0, nil // default is utc
	}
	// hours part maybe zero, can't parse as negative zero
	// so must parse the sign first
	sign := 1 // default is positive
	if t[0] == '+' {
		t = t[1:]
	} else if t[0] == '-' {
		sign = -1
		t = t[1:]
	}

	parts := strings.SplitN(t, ":", 2)
	seconds := 0
	if len(parts) > 1 { // hh:mm
		hours, err := strconv.Atoi(parts[0])
		if err != nil {
			return 0, errors.Wrap(err, errors.NotValidf("%s Not valid", timezone))
		}
		minutes, err := strconv.Atoi(parts[1])
		if err != nil {
			return 0, errors.Wrap(err, errors.NotValidf("%s Not valid", timezone))
		}
		seconds = hours*3600 + minutes*60
	} else { // only hours
		hours, err := strconv.Atoi(parts[0])
		if err != nil {
			return 0, errors.Wrap(err, errors.NotValidf("%s Not valid", timezone))
		}
		seconds = hours * 3600
	}
	seconds = seconds * sign
	return seconds, nil
}

func GetAwsRegionCountryCodeViaShell(region string) (string, error) {
	return RunCommandAndGetOutput("./scripts/get-aws-region-info.sh", "country", region, "--profile=dev")
}
