package collector

import (
	"encoding/json"
	"io"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"
)

type CaddySite struct {
	Domain   string `json:"domain"`
	Upstream string `json:"upstream"`
	TLS      bool   `json:"tls"`
}

type CaddyUpstream struct {
	Address     string `json:"address"`
	NumRequests int    `json:"num_requests"`
	Fails       int    `json:"fails"`
	Healthy     bool   `json:"healthy"`
}

type CaddyData struct {
	Version   string          `json:"version"`
	Sites     []CaddySite     `json:"sites"`
	Upstreams []CaddyUpstream `json:"upstreams,omitempty"`
}

const caddyFile = "/usr/local/etc/caddy/Caddyfile"
const caddyAdminAPI = "http://127.0.0.1:2019"

func CollectCaddy() *CaddyData {
	if _, err := os.Stat(caddyFile); err != nil {
		return nil
	}

	data := &CaddyData{}

	// Version
	if out, err := exec.Command("/usr/local/bin/caddy", "version").Output(); err == nil {
		fields := strings.Fields(strings.TrimSpace(string(out)))
		if len(fields) > 0 {
			data.Version = fields[0]
		}
	}

	// Parse Caddyfile fuer Sites
	content, err := os.ReadFile(caddyFile)
	if err != nil {
		return data
	}

	lines := strings.Split(string(content), "\n")
	var currentDomain string
	var currentTLS bool
	depth := 0

	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if trimmed == "" || strings.HasPrefix(trimmed, "#") {
			continue
		}

		if depth == 0 && strings.Contains(trimmed, "{") {
			parts := strings.Fields(trimmed)
			if len(parts) >= 2 && parts[len(parts)-1] == "{" {
				currentDomain = parts[0]
				currentTLS = !strings.HasPrefix(currentDomain, "http://")
				depth = 1
				continue
			}
		}

		if depth > 0 {
			depth += strings.Count(trimmed, "{") - strings.Count(trimmed, "}")

			if strings.HasPrefix(trimmed, "reverse_proxy") {
				parts := strings.Fields(trimmed)
				if len(parts) >= 2 {
					upstream := parts[1]
					data.Sites = append(data.Sites, CaddySite{
						Domain:   currentDomain,
						Upstream: upstream,
						TLS:      currentTLS,
					})
				}
			}

			if depth <= 0 {
				currentDomain = ""
				depth = 0
			}
		}
	}

	// Admin-API: Upstream-Statistiken
	data.Upstreams = collectCaddyUpstreams()

	return data
}

func collectCaddyUpstreams() []CaddyUpstream {
	client := &http.Client{Timeout: 3 * time.Second}
	resp, err := client.Get(caddyAdminAPI + "/api/reverse_proxy/upstreams")
	if err != nil {
		return nil
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(io.LimitReader(resp.Body, 64*1024))
	if err != nil {
		return nil
	}

	// Admin-API liefert: [{"address":"host:port","num_requests":N,"fails":N}]
	var raw []struct {
		Address     string `json:"address"`
		NumRequests int    `json:"num_requests"`
		Fails       int    `json:"fails"`
	}
	if err := json.Unmarshal(body, &raw); err != nil {
		return nil
	}

	upstreams := make([]CaddyUpstream, 0, len(raw))
	for _, u := range raw {
		upstreams = append(upstreams, CaddyUpstream{
			Address:     u.Address,
			NumRequests: u.NumRequests,
			Fails:       u.Fails,
			Healthy:     u.Fails == 0,
		})
	}
	return upstreams
}
