package provider

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/tidbcloud/aws-shared-provider/tools/cloud-instances/regions"
	"github.com/tidbcloud/aws-shared-provider/tools/cloud-instances/types"
)

// AWSProvider implements the CloudProvider interface for AWS EC2
type AWSProvider struct{}

// NewAWSProvider creates a new AWS provider instance
func NewAWSProvider() *AWSProvider {
	return &AWSProvider{}
}

// AWSInstance represents the raw AWS pricing data structure
type AWSInstance struct {
	Price              string `json:"price"`
	Location           string `json:"Location"`
	InstanceFamily     string `json:"Instance Family"`
	VCPU               string `json:"vCPU"`
	InstanceType       string `json:"Instance Type"`
	Memory             string `json:"Memory"`
	Storage            string `json:"Storage"`
	NetworkPerformance string `json:"Network Performance"`
	OperatingSystem    string `json:"Operating System"`
}

// AWSRegion represents a region with multiple instances
type AWSRegion map[string]AWSInstance

// AWSData represents the full AWS pricing data structure
type AWSData struct {
	Manifest struct {
		ServiceId    string `json:"serviceId"`
		CurrencyCode string `json:"currencyCode"`
	} `json:"manifest"`
	Regions map[string]AWSRegion `json:"regions"`
}

const awsPricingURLTemplate = "https://b0.p.awsstatic.com/pricing/2.0/meteredUnitMaps/ec2/USD/current/ec2-ondemand-without-sec-sel/%s/Linux/index.json?timestsamp=%d"

func (p *AWSProvider) downloadPricing(region string) ([]byte, string, error) {
	regionName := regions.GetAWSRegionName(region)
	url := fmt.Sprintf(awsPricingURLTemplate, regionName, time.Now().UnixMilli())

	client := &http.Client{
		Timeout: 30 * time.Second,
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, "", fmt.Errorf("failed to create request: %v", err)
	}

	// Set headers to mimic browser request
	req.Header.Set("Accept", "*/*")
	req.Header.Set("Sec-Fetch-Site", "same-site")
	req.Header.Set("Origin", "https://aws.amazon.com")
	req.Header.Set("Sec-Fetch-Dest", "empty")
	req.Header.Set("Accept-Language", "en-US,en;q=0.9")
	req.Header.Set("Sec-Fetch-Mode", "cors")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.1 Safari/605.1.15")
	req.Header.Set("Referer", "https://aws.amazon.com/")
	req.Header.Set("Priority", "u=3, i")

	log.Printf("Downloading AWS data for region %s...", region)
	resp, err := client.Do(req)
	if err != nil {
		return nil, "", fmt.Errorf("download failed: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, "", fmt.Errorf("HTTP error: %s", resp.Status)
	}

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, "", fmt.Errorf("failed to read response: %v", err)
	}

	return data, url, nil
}

func (p *AWSProvider) DownloadRaw(region string) (*RawBundle, error) {
	data, url, err := p.downloadPricing(region)
	if err != nil {
		return nil, err
	}

	return &RawBundle{
		Provider: "aws",
		Region:   region,
		Parts: []RawPart{
			{
				Scope:  region,
				Name:   "pricing",
				Data:   data,
				Source: url,
			},
		},
	}, nil
}

func (p *AWSProvider) ParseRaw(raw *RawBundle) (*types.UnifiedData, error) {
	if raw == nil {
		return nil, fmt.Errorf("raw bundle is nil")
	}
	var data []byte
	for _, part := range raw.Parts {
		if part.Name == "pricing" {
			data = part.Data
			break
		}
	}
	if len(data) == 0 {
		return nil, fmt.Errorf("missing pricing data")
	}

	var awsData AWSData
	if err := json.Unmarshal(data, &awsData); err != nil {
		return nil, fmt.Errorf("failed to parse AWS data: %v", err)
	}

	unifiedData := types.NewUnifiedData("aws")
	currency := awsData.Manifest.CurrencyCode
	if currency == "" {
		currency = "USD"
	}

	// Convert AWS format to unified format
	for regionName, regionData := range awsData.Regions {
		// Find the region ID from the display name
		var regionID string
		for id, name := range regions.AWSRegions {
			if name == regionName {
				regionID = id
				break
			}
		}
		if regionID == "" {
			regionID = regionName // fallback
		}

		var instances []types.UnifiedInstance
		for _, instance := range regionData {
			price, err := strconv.ParseFloat(instance.Price, 64)
			if err != nil {
				// Skip instances with invalid price
				continue
			}

			unifiedInstance := types.UnifiedInstance{
				Provider:           "aws",
				InstanceType:       instance.InstanceType,
				InstanceFamily:     instance.InstanceFamily,
				VCPU:               instance.VCPU,
				Memory:             instance.Memory,
				Storage:            instance.Storage,
				NetworkPerformance: instance.NetworkPerformance,
				Price:              price,
				Currency:           currency,
				Location:           instance.Location,
				Region:             regionID,
			}
			instances = append(instances, unifiedInstance)
		}

		if len(instances) > 0 {
			unifiedData.Instances[regionID] = instances
		}
	}

	return unifiedData, nil
}

func (p *AWSProvider) GetRegions() map[string]string {
	return regions.AWSRegions
}

func (p *AWSProvider) IsValidRegion(regionID string) bool {
	return regions.IsValidAWSRegion(regionID)
}

func (p *AWSProvider) GetRegionName(regionID string) string {
	return regions.GetAWSRegionName(regionID)
}

func (p *AWSProvider) GetCacheFileName(region string) string {
	return fmt.Sprintf("aws_%s.json", region)
}

func (p *AWSProvider) GetProviderName() string {
	return "aws"
}
