// internal/config/jwt.go
package config

import (
	"errors"
	"os"
	"time"

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

var jwtConfig *JWTConfig

// JWTConfig holds JWT configuration
type JWTConfig struct {
	SecretKey       string
	ExpirationHours int
	Issuer          string
}

// JWTClaims represents the JWT claims
type JWTClaims struct {
	UserID uint   `json:"user_id"`
	Email  string `json:"email"`
	Role   string `json:"role"`
	jwt.RegisteredClaims
}

// InitJWT initializes JWT configuration
func InitJWT() {
	secretKey := os.Getenv("JWT_SECRET_KEY")
	if secretKey == "" {
		secretKey = "your-secret-key-change-this-in-production" // Default for development
	}

	jwtConfig = &JWTConfig{
		SecretKey:       secretKey,
		ExpirationHours: 24 * 7, // 7 days
		Issuer:          "lost-and-found-system",
	}
}

// GetJWTConfig returns JWT configuration
func GetJWTConfig() JWTConfig {
	if jwtConfig == nil {
		InitJWT()
	}
	return *jwtConfig
}

// GenerateToken generates a new JWT token for a user
func GenerateToken(userID uint, email, role string) (string, error) {
	config := GetJWTConfig()

	// Create claims
	claims := JWTClaims{
		UserID: userID,
		Email:  email,
		Role:   role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(config.ExpirationHours))),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			Issuer:    config.Issuer,
		},
	}

	// Create token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// Sign token with secret key
	tokenString, err := token.SignedString([]byte(config.SecretKey))
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

// ValidateToken validates a JWT token and returns the claims
func ValidateToken(tokenString string) (*JWTClaims, error) {
	config := GetJWTConfig()

	// Parse token
	token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
		// Validate signing method
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("invalid signing method")
		}
		return []byte(config.SecretKey), nil
	})

	if err != nil {
		return nil, err
	}

	// Extract claims
	if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token")
}

// RefreshToken generates a new token with extended expiration
func RefreshToken(oldTokenString string) (string, error) {
	// Validate old token
	claims, err := ValidateToken(oldTokenString)
	if err != nil {
		return "", err
	}

	// Generate new token with same user info
	return GenerateToken(claims.UserID, claims.Email, claims.Role)
}

// ExtractUserID extracts user ID from token string
func ExtractUserID(tokenString string) (uint, error) {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return 0, err
	}
	return claims.UserID, nil
}

// ExtractRole extracts role from token string
func ExtractRole(tokenString string) (string, error) {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return "", err
	}
	return claims.Role, nil
}