package auth

import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

// Claims represents JWT payload
type Claims struct {
	UserID      string `json:"user_id"`
	CommunityID string `json:"community_id"`
	Username    string `json:"username"`
	IssuedAt    int64  `json:"iat"`
	ExpiresAt   int64  `json:"exp"`
}

var jwtSecret = []byte("CHANGE-THIS-IN-PRODUCTION-USE-ENV-VAR") // TODO: Load from env

// GenerateJWT creates a signed JWT token
func GenerateJWT(userID, communityID, username string, duration time.Duration) (string, error) {
	now := time.Now()
	claims := Claims{
		UserID:      userID,
		CommunityID: communityID,
		Username:    username,
		IssuedAt:    now.Unix(),
		ExpiresAt:   now.Add(duration).Unix(),
	}

	// Create header
	header := map[string]string{
		"alg": "HS256",
		"typ": "JWT",
	}

	headerJSON, _ := json.Marshal(header)
	claimsJSON, _ := json.Marshal(claims)

	// Base64URL encode
	headerB64 := base64.RawURLEncoding.EncodeToString(headerJSON)
	claimsB64 := base64.RawURLEncoding.EncodeToString(claimsJSON)

	// Create signature
	message := headerB64 + "." + claimsB64
	signature := createSignature(message)

	return message + "." + signature, nil
}

// VerifyJWT validates and parses a JWT token
func VerifyJWT(token string) (*Claims, error) {
	parts := strings.Split(token, ".")
	if len(parts) != 3 {
		return nil, fmt.Errorf("invalid token format")
	}

	// Verify signature
	message := parts[0] + "." + parts[1]
	expectedSig := createSignature(message)
	if parts[2] != expectedSig {
		return nil, fmt.Errorf("invalid signature")
	}

	// Decode claims
	claimsJSON, err := base64.RawURLEncoding.DecodeString(parts[1])
	if err != nil {
		return nil, fmt.Errorf("failed to decode claims: %w", err)
	}

	var claims Claims
	if err := json.Unmarshal(claimsJSON, &claims); err != nil {
		return nil, fmt.Errorf("failed to parse claims: %w", err)
	}

	// Check expiration
	if time.Now().Unix() > claims.ExpiresAt {
		return nil, fmt.Errorf("token expired")
	}

	return &claims, nil
}

// createSignature generates HMAC-SHA256 signature
func createSignature(message string) string {
	h := hmac.New(sha256.New, jwtSecret)
	h.Write([]byte(message))
	return base64.RawURLEncoding.EncodeToString(h.Sum(nil))
}

// GenerateSessionToken creates a cryptographically secure session token
func GenerateSessionToken() (string, error) {
	token := make([]byte, 32)
	if _, err := rand.Read(token); err != nil {
		return "", err
	}
	return base64.RawURLEncoding.EncodeToString(token), nil
}

// HashToken creates SHA256 hash for database storage
func HashToken(token string) string {
	hash := sha256.Sum256([]byte(token))
	return base64.RawURLEncoding.EncodeToString(hash[:])
}
