package main

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

	"github.com/golang-jwt/jwt/v5"
)

var jwtSecret = func() []byte {
	if s := os.Getenv("IC3_JWT_SECRET"); s != "" {
		return []byte(s)
	}
	return []byte("ic3-dashboard-secret-2026-change-in-prod")
}()

type Claims struct {
	Username string `json:"username"`
	Role     string `json:"role"`
	UserID   int64  `json:"user_id"`
	jwt.RegisteredClaims
}

type ctxKey string

const claimsCtxKey ctxKey = "claims"

// claimsFrom extracts the JWT claims stored by authMiddleware.
func claimsFrom(r *http.Request) *Claims {
	c, _ := r.Context().Value(claimsCtxKey).(*Claims)
	return c
}

// authMiddleware validates the Bearer token and stores claims in context.
func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodOptions {
			next(w, r)
			return
		}
		if os.Getenv("IC3_SKIP_AUTH") == "true" {
			next(w, r)
			return
		}
		auth := r.Header.Get("Authorization")
		if !strings.HasPrefix(auth, "Bearer ") {
			w.WriteHeader(401)
			json.NewEncoder(w).Encode(map[string]string{"error": "unauthorized"})
			return
		}
		claims := &Claims{}
		_, err := jwt.ParseWithClaims(
			strings.TrimPrefix(auth, "Bearer "),
			claims,
			func(t *jwt.Token) (any, error) { return jwtSecret, nil },
		)
		if err != nil {
			w.WriteHeader(401)
			json.NewEncoder(w).Encode(map[string]string{"error": "invalid token"})
			return
		}
		ctx := context.WithValue(r.Context(), claimsCtxKey, claims)
		next(w, r.WithContext(ctx))
	}
}

// adminOnly wraps a handler so only admin-role tokens can reach it.
func adminOnly(next http.HandlerFunc) http.HandlerFunc {
	return authMiddleware(func(w http.ResponseWriter, r *http.Request) {
		c := claimsFrom(r)
		if c == nil || (c.Role != "admin" && c.Role != "SUPER_ADMIN") {
			w.WriteHeader(403)
			json.NewEncoder(w).Encode(map[string]string{"error": "admin access required"})
			return
		}
		next(w, r)
	})
}
