package api

import (
	"context"
	"encoding/json"
	"net/http"

	cf "gitea.dooplex.hu/admin/felhom-controller/internal/cloudflare"
	"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
)

func (r *Router) geoStatus(w http.ResponseWriter, _ *http.Request) {
	geo := r.sett.GetGeoRestriction()

	data := map[string]interface{}{
		"cf_configured": r.cfg.Infrastructure.CFAPIToken != "",
		"geo_available": r.geoSync != nil,
	}

	if geo != nil {
		data["enabled"] = geo.Enabled
		data["allowed_countries"] = geo.AllowedCountries
		data["app_overrides"] = geo.AppOverrides
		data["last_sync"] = geo.LastSync
		data["last_sync_error"] = geo.LastSyncError
		data["syncing"] = r.geoSync != nil && r.geoSync.IsRunning()
	} else {
		data["enabled"] = false
		data["allowed_countries"] = []string{"HU"}
	}

	writeJSON(w, http.StatusOK, apiResponse{OK: true, Data: data})
}

func (r *Router) geoUpdateSettings(w http.ResponseWriter, req *http.Request) {
	limitBody(w, req)
	r.dbg("geoUpdateSettings: contentLength=%d", req.ContentLength)

	var body struct {
		Enabled          bool     `json:"enabled"`
		AllowedCountries []string `json:"allowed_countries"`
	}
	if err := json.NewDecoder(req.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, apiResponse{OK: false, Error: "invalid request body"})
		return
	}

	// Validate country codes
	for _, code := range body.AllowedCountries {
		if !cf.ValidCountryCode(code) {
			writeJSON(w, http.StatusBadRequest, apiResponse{OK: false, Error: "invalid country code: " + code})
			return
		}
	}

	// Get existing settings to preserve app overrides and sync state
	existing := r.sett.GetGeoRestriction()
	geo := &settings.GeoRestriction{
		Enabled:          body.Enabled,
		AllowedCountries: body.AllowedCountries,
	}
	if existing != nil {
		geo.AppOverrides = existing.AppOverrides
		geo.ZoneID = existing.ZoneID
		geo.RulesetID = existing.RulesetID
	}

	if err := r.sett.SetGeoRestriction(geo); err != nil {
		r.logger.Printf("[ERROR] [api] Failed to save geo settings: %v", err)
		writeJSON(w, http.StatusInternalServerError, apiResponse{OK: false, Error: err.Error()})
		return
	}

	r.logger.Printf("[INFO] [api] Geo settings updated: enabled=%v, countries=%v", body.Enabled, body.AllowedCountries)

	// Trigger async CF sync
	if r.geoSync != nil {
		go func() {
			if err := r.geoSync.Sync(context.Background()); err != nil {
				r.logger.Printf("[ERROR] [api] Geo sync after settings update failed: %v", err)
			}
		}()
	}

	// Push a fresh hub report out-of-band so the hub reflects the new geo state right
	// away instead of after the next ~15-min cycle.
	r.reportPushNow()

	writeJSON(w, http.StatusOK, apiResponse{OK: true, Message: "Geo-korlátozás beállítva"})
}

func (r *Router) geoTriggerSync(w http.ResponseWriter, _ *http.Request) {
	if r.geoSync == nil {
		writeJSON(w, http.StatusBadRequest, apiResponse{OK: false, Error: "Cloudflare API nincs konfigurálva"})
		return
	}

	go func() {
		if err := r.geoSync.Sync(context.Background()); err != nil {
			r.logger.Printf("[ERROR] [api] Manual geo sync failed: %v", err)
			return
		}
		// On success the sync clears any stale last_sync_error — push a report so the hub
		// reflects the cleared state immediately rather than after the next cycle.
		r.reportPushNow()
	}()

	writeJSON(w, http.StatusOK, apiResponse{OK: true, Message: "Szinkronizálás elindítva"})
}

func (r *Router) geoCountries(w http.ResponseWriter, _ *http.Request) {
	writeJSON(w, http.StatusOK, apiResponse{OK: true, Data: cf.AllCountries()})
}

func (r *Router) geoSetAppOverride(w http.ResponseWriter, req *http.Request, appName string) {
	if appName == "" {
		writeJSON(w, http.StatusBadRequest, apiResponse{OK: false, Error: "invalid app name"})
		return
	}
	limitBody(w, req)

	var body struct {
		AllowedCountries []string `json:"allowed_countries"`
	}
	if err := json.NewDecoder(req.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, apiResponse{OK: false, Error: "invalid request body"})
		return
	}

	// Validate country codes
	for _, code := range body.AllowedCountries {
		if !cf.ValidCountryCode(code) {
			writeJSON(w, http.StatusBadRequest, apiResponse{OK: false, Error: "invalid country code: " + code})
			return
		}
	}

	// Verify app exists
	if _, ok := r.stackMgr.GetStack(appName); !ok {
		writeJSON(w, http.StatusNotFound, apiResponse{OK: false, Error: "app not found: " + appName})
		return
	}

	override := &settings.AppGeoOverride{AllowedCountries: body.AllowedCountries}
	if err := r.sett.SetGeoAppOverride(appName, override); err != nil {
		r.logger.Printf("[ERROR] [api] Failed to save geo override for %s: %v", appName, err)
		writeJSON(w, http.StatusInternalServerError, apiResponse{OK: false, Error: err.Error()})
		return
	}

	r.logger.Printf("[INFO] [api] Geo override set for %s: countries=%v", appName, body.AllowedCountries)

	// Trigger async CF sync
	if r.geoSync != nil {
		go func() {
			if err := r.geoSync.Sync(context.Background()); err != nil {
				r.logger.Printf("[ERROR] [api] Geo sync after app override failed: %v", err)
			}
		}()
	}

	writeJSON(w, http.StatusOK, apiResponse{OK: true, Message: "Alkalmazás geo-korlátozás beállítva"})
}

func (r *Router) geoRemoveAppOverride(w http.ResponseWriter, _ *http.Request, appName string) {
	if appName == "" {
		writeJSON(w, http.StatusBadRequest, apiResponse{OK: false, Error: "invalid app name"})
		return
	}

	if err := r.sett.RemoveGeoAppOverride(appName); err != nil {
		r.logger.Printf("[ERROR] [api] Failed to remove geo override for %s: %v", appName, err)
		writeJSON(w, http.StatusInternalServerError, apiResponse{OK: false, Error: err.Error()})
		return
	}

	r.logger.Printf("[INFO] [api] Geo override removed for %s", appName)

	// Trigger async CF sync
	if r.geoSync != nil {
		go func() {
			if err := r.geoSync.Sync(context.Background()); err != nil {
				r.logger.Printf("[ERROR] [api] Geo sync after override removal failed: %v", err)
			}
		}()
	}

	writeJSON(w, http.StatusOK, apiResponse{OK: true, Message: "Alkalmazás geo-korlátozás eltávolítva"})
}
