package web

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"sync"
	"time"
)

const templateRawURL = "https://gitea.dooplex.hu/admin/felhom-controller/raw/branch/main/controller/configs/controller.yaml.example"

// TemplateFetcher periodically fetches controller.yaml.example from the Gitea
// repo and caches it for config generation. Falls back to go:embed default.
type TemplateFetcher struct {
	username      string
	token         string
	fetchInterval time.Duration
	logger        *log.Logger

	mu             sync.RWMutex
	cachedTemplate string
	lastFetch      time.Time
	lastError      string
}

// NewTemplateFetcher creates a new TemplateFetcher.
func NewTemplateFetcher(username, token string, fetchInterval time.Duration, logger *log.Logger) *TemplateFetcher {
	return &TemplateFetcher{
		username:      username,
		token:         token,
		fetchInterval: fetchInterval,
		logger:        logger,
	}
}

// Run starts the periodic fetch loop. Call in a goroutine.
// It fetches immediately on start, then every fetchInterval.
func (tf *TemplateFetcher) Run(ctx context.Context) {
	tf.fetch()
	ticker := time.NewTicker(tf.fetchInterval)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			tf.fetch()
		}
	}
}

func (tf *TemplateFetcher) fetch() {
	req, err := http.NewRequest("GET", templateRawURL, nil)
	if err != nil {
		tf.mu.Lock()
		tf.lastError = err.Error()
		tf.mu.Unlock()
		tf.logger.Printf("[WARN] Template fetch: failed to create request: %v", err)
		return
	}
	if tf.username != "" && tf.token != "" {
		req.SetBasicAuth(tf.username, tf.token)
	}

	client := &http.Client{Timeout: 15 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		tf.mu.Lock()
		tf.lastError = err.Error()
		tf.mu.Unlock()
		tf.logger.Printf("[WARN] Template fetch: HTTP request failed: %v", err)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		tf.mu.Lock()
		tf.lastError = fmt.Sprintf("HTTP %d", resp.StatusCode)
		tf.mu.Unlock()
		tf.logger.Printf("[WARN] Template fetch: unexpected status %d", resp.StatusCode)
		return
	}

	body, err := io.ReadAll(io.LimitReader(resp.Body, 64*1024)) // 64KB max
	if err != nil {
		tf.mu.Lock()
		tf.lastError = err.Error()
		tf.mu.Unlock()
		tf.logger.Printf("[WARN] Template fetch: read error: %v", err)
		return
	}

	tf.mu.Lock()
	tf.cachedTemplate = string(body)
	tf.lastFetch = time.Now()
	tf.lastError = ""
	tf.mu.Unlock()
	tf.logger.Printf("[DEBUG] Template fetched (%d bytes)", len(body))
}

// Template returns the cached controller.yaml template.
// If the cache is empty (never fetched or all failures), returns the go:embed fallback.
func (tf *TemplateFetcher) Template() string {
	tf.mu.RLock()
	defer tf.mu.RUnlock()
	if tf.cachedTemplate != "" {
		return tf.cachedTemplate
	}
	return defaultControllerTemplate
}
