package main

import (
	"embed"
	"encoding/json"
	"io/fs"
	"log"
	"net/http"
	"strings"
)

//go:embed web
var webFS embed.FS

type server struct {
	state *State
	mux   *http.ServeMux
}

func newServer(st *State) *server {
	s := &server{state: st, mux: http.NewServeMux()}

	// Статика (HTML/CSS/JS из embed)
	sub, _ := fs.Sub(webFS, "web")
	s.mux.Handle("/", http.FileServer(http.FS(sub)))

	// API
	s.mux.HandleFunc("/api/state", s.handleState)
	s.mux.HandleFunc("/api/precheck", s.handlePrecheck)
	s.mux.HandleFunc("/api/config", s.handleConfig)
	s.mux.HandleFunc("/api/install", s.handleInstall)
	s.mux.HandleFunc("/api/events", s.handleSSE)
	s.mux.HandleFunc("/api/reset", s.handleReset)

	return s
}

func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Защита: только localhost (даже если addr 0.0.0.0 поставят)
	host := r.RemoteAddr
	if i := strings.LastIndex(host, ":"); i != -1 {
		host = host[:i]
	}
	switch host {
	case "127.0.0.1", "::1", "[::1]", "localhost":
		// ok
	default:
		http.Error(w, "installer is local-only", http.StatusForbidden)
		return
	}
	s.mux.ServeHTTP(w, r)
}

// GET /api/state — полный snapshot для холодного открытия страницы.
func (s *server) handleState(w http.ResponseWriter, r *http.Request) {
	snap := s.state.Snapshot()
	writeJSON(w, snap)
}

// POST /api/precheck — запускает все pre-check проверки и возвращает результат.
// Wizard переходит на стадию precheck.
func (s *server) handlePrecheck(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	s.state.setStage(StagePrecheck)
	results := runPrechecks(s.state.artifactsDir)
	s.state.setPrecheck(results)
	writeJSON(w, results)
}

// POST /api/config — сохраняет org INN, email, license. Переход на стадию config.
func (s *server) handleConfig(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	var c Config
	if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
		http.Error(w, "invalid json", http.StatusBadRequest)
		return
	}
	s.state.setConfig(c)
	s.state.setStage(StageConfig)
	writeJSON(w, map[string]bool{"ok": true})
}

// POST /api/install — стартует установку (в горутине), переход на стадию installing.
// UI слушает /api/events для прогресса.
func (s *server) handleInstall(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	s.state.setStage(StageInstalling)
	go func() {
		if err := runInstallation(s.state); err != nil {
			log.Printf("install error: %v", err)
			s.state.setError(err.Error())
			return
		}
		s.state.setStage(StageDone)
	}()
	writeJSON(w, map[string]bool{"ok": true})
}

// POST /api/reset — сброс wizard'а на welcome (после ошибки).
func (s *server) handleReset(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	s.state.mu.Lock()
	s.state.Stage = StageWelcome
	s.state.ErrorMsg = ""
	s.state.Precheck = nil
	s.state.Steps = buildStepList()
	s.state.mu.Unlock()
	s.state.bus.publish(event{Type: "reset", Data: "{}"})
	writeJSON(w, map[string]bool{"ok": true})
}

func writeJSON(w http.ResponseWriter, v any) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	enc := json.NewEncoder(w)
	enc.SetIndent("", "  ")
	_ = enc.Encode(v)
}
