package rest

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

	"github.com/explorer/backend/auth"
)

// handleAuthRefresh implements POST /api/v1/auth/refresh.
//
// Contract:
//   - Requires a valid, unrevoked wallet JWT in the Authorization header.
//   - Mints a new JWT for the same address+track with a fresh jti and a
//     fresh per-track TTL.
//   - Revokes the presented token so it cannot be reused.
//
// This is the mechanism that makes the short Track-4 TTL (60 min in
// PR #8) acceptable: operators refresh while the token is still live
// rather than re-signing a SIWE message every hour.
func (s *Server) handleAuthRefresh(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
		return
	}
	if s.walletAuth == nil {
		writeError(w, http.StatusServiceUnavailable, "service_unavailable", "wallet auth not configured")
		return
	}

	token := extractBearerToken(r)
	if token == "" {
		writeError(w, http.StatusUnauthorized, "unauthorized", "missing or malformed Authorization header")
		return
	}

	resp, err := s.walletAuth.RefreshJWT(r.Context(), token)
	if err != nil {
		switch {
		case errors.Is(err, auth.ErrJWTRevoked):
			writeError(w, http.StatusUnauthorized, "token_revoked", err.Error())
		case errors.Is(err, auth.ErrWalletAuthStorageNotInitialized):
			writeError(w, http.StatusServiceUnavailable, "service_unavailable", err.Error())
		default:
			writeError(w, http.StatusUnauthorized, "unauthorized", err.Error())
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	_ = json.NewEncoder(w).Encode(resp)
}

// handleAuthLogout implements POST /api/v1/auth/logout.
//
// Records the presented token's jti in jwt_revocations so subsequent
// calls to ValidateJWT will reject it. Idempotent: logging out twice
// with the same token succeeds.
func (s *Server) handleAuthLogout(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
		return
	}
	if s.walletAuth == nil {
		writeError(w, http.StatusServiceUnavailable, "service_unavailable", "wallet auth not configured")
		return
	}

	token := extractBearerToken(r)
	if token == "" {
		writeError(w, http.StatusUnauthorized, "unauthorized", "missing or malformed Authorization header")
		return
	}

	if err := s.walletAuth.RevokeJWT(r.Context(), token, "logout"); err != nil {
		switch {
		case errors.Is(err, auth.ErrJWTRevocationStorageMissing):
			// Surface 503 so ops know migration 0016 hasn't run; the
			// client should treat the token as logged out locally.
			writeError(w, http.StatusServiceUnavailable, "service_unavailable", err.Error())
		default:
			writeError(w, http.StatusUnauthorized, "unauthorized", err.Error())
		}
		return
	}

	w.Header().Set("Content-Type", "application/json")
	_ = json.NewEncoder(w).Encode(map[string]any{
		"status": "ok",
	})
}
