package controlplane

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"
)

type Backend struct {
	Host string `json:"host"`
	Port int    `json:"port"`
}

type ResolveResponse struct {
	ServerID           string   `json:"serverId"`
	Slug               string   `json:"slug"`
	Status             string   `json:"status"`
	JoinToStartEnabled bool     `json:"joinToStartEnabled"`
	Edition            string   `json:"edition"`
	Backend            *Backend `json:"backend"`
	Action             string   `json:"action"`
	Message            string   `json:"message,omitempty"`
}

type StartResponse struct {
	Resolve       ResolveResponse `json:"resolve"`
	Started       bool            `json:"started"`
	JobID         string          `json:"jobId,omitempty"`
	QueuePosition int             `json:"queuePosition,omitempty"`
}

type Client struct {
	baseURL    string
	edgeKey    string
	httpClient *http.Client
}

func NewClient(baseURL, edgeKey string) *Client {
	return &Client{
		baseURL: baseURL,
		edgeKey: edgeKey,
		httpClient: &http.Client{
			Timeout: 15 * time.Second,
		},
	}
}

func (c *Client) Resolve(slug, clientIP string) (*ResolveResponse, error) {
	endpoint := fmt.Sprintf("%s/internal/edge/v1/resolve/%s", c.baseURL, url.PathEscape(slug))
	if clientIP != "" {
		endpoint = endpoint + "?clientIp=" + url.QueryEscape(clientIP)
	}

	req, err := http.NewRequest(http.MethodGet, endpoint, nil)
	if err != nil {
		return nil, err
	}
	c.applyHeaders(req)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusNotFound {
		return nil, fmt.Errorf("unknown slug")
	}
	if resp.StatusCode >= 400 {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("resolve failed: %s", string(body))
	}

	var result ResolveResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}
	return &result, nil
}

func (c *Client) Start(slug, clientIP string) (*StartResponse, error) {
	endpoint := fmt.Sprintf("%s/internal/edge/v1/start/%s", c.baseURL, url.PathEscape(slug))
	payload, err := json.Marshal(map[string]string{"clientIp": clientIP})
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewReader(payload))
	if err != nil {
		return nil, err
	}
	c.applyHeaders(req)
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("start failed: %s", string(body))
	}

	var result StartResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}
	return &result, nil
}

func (c *Client) applyHeaders(req *http.Request) {
	req.Header.Set("X-HexaHost-Edge-Key", c.edgeKey)
}
