package auth

import (
	"context"
	"errors"
	"net/http"

	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgxpool"

	"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
)

type ctxKey int

const userCtxKey ctxKey = 1

// RequireAdmin gates a handler on X-API-Token matching an admin user. This is
// the Minstrel-native token path (`/api/*`); Subsonic-compatible auth under
// `/rest/*` lands with the Subsonic server.
func RequireAdmin(pool *pgxpool.Pool) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			token := r.Header.Get("X-API-Token")
			if token == "" {
				http.Error(w, "missing X-API-Token", http.StatusUnauthorized)
				return
			}
			q := dbq.New(pool)
			user, err := q.GetUserByAPIToken(r.Context(), token)
			if err != nil {
				if errors.Is(err, pgx.ErrNoRows) {
					http.Error(w, "invalid token", http.StatusUnauthorized)
					return
				}
				http.Error(w, "auth lookup failed", http.StatusInternalServerError)
				return
			}
			if !user.IsAdmin {
				http.Error(w, "admin required", http.StatusForbidden)
				return
			}
			ctx := context.WithValue(r.Context(), userCtxKey, user)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

// UserFromContext returns the authenticated user when the request passed
// through RequireAdmin (or a future RequireUser middleware).
func UserFromContext(ctx context.Context) (dbq.User, bool) {
	u, ok := ctx.Value(userCtxKey).(dbq.User)
	return u, ok
}
