package httpapi

import (
	"encoding/json"
	"io"
	"log/slog"
	"net/http"
	"time"
)

type refreshReq struct {
	RefreshToken string `json:"refresh_token"`
}

type refreshResp struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int    `json:"expires_in"`
}

// handleAuthRefresh proxies a token refresh to the Auth Broker. The SPA holds a
// broker-minted access + refresh; when the access expires it POSTs the refresh token
// here and cdrop relays it to the broker's /refresh, returning the rotated pair. The
// proxy keeps the browser same-origin (no broker CORS) and means cdrop stores no
// credential — it only forwards. Public (the access token is expired, which is the
// point); Origin-checked for CSRF.
func (s *Server) handleAuthRefresh(w http.ResponseWriter, r *http.Request) {
	if !s.sameOrigin(r) {
		writeJSON(w, http.StatusForbidden, map[string]string{"error": "bad origin"})
		return
	}
	var req refreshReq
	if err := json.NewDecoder(io.LimitReader(r.Body, 8192)).Decode(&req); err != nil {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid json"})
		return
	}
	if req.RefreshToken == "" {
		writeJSON(w, http.StatusBadRequest, map[string]string{"error": "missing refresh token"})
		return
	}

	res, err := s.broker.RefreshSession(r.Context(), req.RefreshToken)
	if err != nil {
		// A rejected refresh (expired / rotated / revoked) is the client's cue to
		// re-authenticate; relay it as 401. (A broker outage also lands here — rare,
		// and re-login is the safe fallback.)
		slog.Warn("broker refresh failed", "err", err)
		writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "refresh rejected"})
		return
	}

	expiresIn := int(res.AccessExpires - time.Now().Unix())
	if expiresIn < 0 {
		expiresIn = 0
	}
	writeJSON(w, http.StatusOK, refreshResp{
		AccessToken:  res.Access,
		RefreshToken: res.Refresh,
		ExpiresIn:    expiresIn,
	})
}
