package handlers

import (
	"encoding/json"
	"errors"
	"net/http"
	"os"
	"strings"

	agentbackup "zlh-agent/internal/backup"
	"zlh-agent/internal/state"
)

var loadBackupConfig = state.LoadConfig
var restoreBackup = agentbackup.Restore

func HandleGameBackups(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		handleGameBackupsList(w, r)
	case http.MethodPost:
		handleGameBackupCreate(w, r)
	default:
		writeJSONError(w, http.StatusMethodNotAllowed, "GET or POST only")
	}
}

func HandleGameBackupByID(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodDelete {
		writeJSONError(w, http.StatusMethodNotAllowed, "DELETE only")
		return
	}
	endOp, ok := beginHandlerOperation(w, "backup_delete", true, "deleting backup")
	if !ok {
		return
	}
	defer endOp()

	if _, ok := requireBackupConfig(w); !ok {
		return
	}

	id := strings.TrimPrefix(r.URL.Path, "/game/backups/")
	id = strings.TrimSpace(strings.Trim(id, "/"))
	if id == "" || strings.Contains(id, "/") {
		writeJSONError(w, http.StatusBadRequest, "backup id required")
		return
	}

	if err := agentbackup.Delete(id); err != nil {
		if errors.Is(err, os.ErrNotExist) {
			writeJSONError(w, http.StatusNotFound, "backup not found")
			return
		}
		writeJSONError(w, http.StatusBadRequest, err.Error())
		return
	}
	writeJSON(w, http.StatusOK, map[string]any{"deleted": true, "id": id})
}

func handleGameBackupsList(w http.ResponseWriter, r *http.Request) {
	if _, ok := requireBackupConfig(w); !ok {
		return
	}
	backups, err := agentbackup.List()
	if err != nil {
		writeJSONError(w, http.StatusInternalServerError, err.Error())
		return
	}
	writeJSON(w, http.StatusOK, map[string]any{"backups": backups})
}

func handleGameBackupCreate(w http.ResponseWriter, r *http.Request) {
	endOp, ok := beginHandlerOperation(w, "backup_create", true, "creating backup")
	if !ok {
		return
	}
	defer endOp()

	cfg, ok := requireBackupConfig(w)
	if !ok {
		return
	}
	manifest, err := agentbackup.Create(cfg)
	if err != nil {
		writeJSONError(w, http.StatusInternalServerError, err.Error())
		return
	}
	writeJSON(w, http.StatusOK, manifest)
}

func HandleGameBackupRestore(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeJSONError(w, http.StatusMethodNotAllowed, "POST only")
		return
	}
	endOp, ok := beginHandlerOperation(w, "backup_restore", true, "restoring backup")
	if !ok {
		return
	}
	defer endOp()

	cfg, ok := requireBackupConfig(w)
	if !ok {
		return
	}

	id := strings.TrimSpace(r.URL.Query().Get("id"))
	if id == "" {
		var req struct {
			ID string `json:"id"`
		}
		_ = json.NewDecoder(r.Body).Decode(&req)
		id = strings.TrimSpace(req.ID)
	}
	if id == "" {
		writeJSONError(w, http.StatusBadRequest, "backup id required")
		return
	}

	result, err := restoreBackup(cfg, id)
	if err != nil {
		writeJSONError(w, http.StatusInternalServerError, err.Error())
		return
	}
	writeJSON(w, http.StatusOK, map[string]any{
		"restored":   true,
		"backup":     result.Backup,
		"checkpoint": result.Checkpoint,
	})
}

func requireBackupConfig(w http.ResponseWriter) (*state.Config, bool) {
	cfg, err := loadBackupConfig()
	if err != nil {
		writeJSONError(w, http.StatusBadRequest, "no config loaded")
		return nil, false
	}
	if !strings.EqualFold(cfg.ContainerType, "game") {
		writeJSONError(w, http.StatusBadRequest, "not a game container")
		return nil, false
	}
	if !strings.EqualFold(cfg.Game, "minecraft") {
		writeJSONError(w, http.StatusNotImplemented, "backups are only implemented for minecraft")
		return nil, false
	}
	return cfg, true
}
