package updater

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"

	"github.com/qdm12/gluetun/internal/provider/surfshark/servers"
)

func addServersFromAPI(ctx context.Context, client *http.Client,
	hts hostToServers,
) (err error) {
	data, err := fetchAPI(ctx, client)
	if err != nil {
		return err
	}

	locationData := servers.LocationData()
	hostToLocation := hostToLocation(locationData)

	for _, serverData := range data {
		locationData := hostToLocation[serverData.Host] // TODO remove in v4
		retroLoc := locationData.RetroLoc               // empty string if the host has no retro-compatible region

		tcp, udp := true, true // OpenVPN servers from API supports both TCP and UDP
		hts.addOpenVPN(serverData.Host, serverData.Region, serverData.Country,
			serverData.Location, retroLoc, tcp, udp)

		if serverData.PubKey != "" {
			hts.addWireguard(serverData.Host, serverData.Region, serverData.Country,
				serverData.Location, retroLoc, serverData.PubKey)
		}
	}

	return nil
}

var ErrHTTPStatusCodeNotOK = errors.New("HTTP status code not OK")

type serverData struct {
	Host     string `json:"connectionName"`
	Region   string `json:"region"`
	Country  string `json:"country"`
	Location string `json:"location"`
	PubKey   string `json:"pubKey"`
}

func fetchAPI(ctx context.Context, client *http.Client) (
	servers []serverData, err error,
) {
	const url = "https://api.surfshark.com/v4/server/clusters"

	for _, clustersType := range [...]string{"generic", "double", "static", "obfuscated"} {
		request, err := http.NewRequestWithContext(ctx, http.MethodGet, url+"/"+clustersType, nil)
		if err != nil {
			return nil, err
		}

		response, err := client.Do(request)
		if err != nil {
			return nil, err
		}
		defer response.Body.Close()

		if response.StatusCode != http.StatusOK {
			return nil, fmt.Errorf("%w: %d %s", ErrHTTPStatusCodeNotOK,
				response.StatusCode, response.Status)
		}

		decoder := json.NewDecoder(response.Body)
		var newServers []serverData
		err = decoder.Decode(&newServers)
		if err != nil {
			return nil, fmt.Errorf("decoding response body: %w", err)
		}

		err = response.Body.Close()
		if err != nil {
			return nil, err
		}

		servers = append(servers, newServers...)
	}

	return servers, nil
}
