package service

import (
	"context"
	"errors"
	"fmt"
	"strconv"

	"github.com/ez-api/foundation/tokenhash"
	"github.com/redis/go-redis/v9"
)

type TokenService struct {
	rdb *redis.Client
}

func NewTokenService(rdb *redis.Client) *TokenService {
	return &TokenService{rdb: rdb}
}

type TokenInfo struct {
	MasterID      uint
	IssuedAtEpoch int64
	Status        string
	Group         string
}

// ValidateToken checks a child key against Redis for validity.
// This is designed to be called by the data plane (balancer).
func (s *TokenService) ValidateToken(ctx context.Context, token string) (*TokenInfo, error) {
	tokenHash := tokenhash.HashToken(token)
	tokenKey := fmt.Sprintf("auth:token:%s", tokenHash)

	// 1. Get token metadata from Redis
	tokenData, err := s.rdb.HGetAll(ctx, tokenKey).Result()
	if err != nil {
		return nil, fmt.Errorf("failed to get token data: %w", err)
	}
	if len(tokenData) == 0 {
		return nil, errors.New("token not found")
	}

	if tokenData["status"] != "active" {
		return nil, errors.New("token is not active")
	}

	masterID, _ := strconv.ParseUint(tokenData["master_id"], 10, 64)
	issuedAtEpoch, _ := strconv.ParseInt(tokenData["issued_at_epoch"], 10, 64)

	// 2. Get master metadata from Redis
	masterKey := fmt.Sprintf("auth:master:%d", masterID)
	masterData, err := s.rdb.HGetAll(ctx, masterKey).Result()
	if err != nil {
		return nil, fmt.Errorf("failed to get master metadata: %w", err)
	}
	if len(masterData) == 0 {
		return nil, errors.New("master metadata not found")
	}
	masterStatus := masterData["status"]
	if masterStatus != "" && masterStatus != "active" {
		return nil, errors.New("master is not active")
	}
	masterEpoch, _ := strconv.ParseInt(masterData["epoch"], 10, 64)

	// 3. Core Epoch Validation
	if issuedAtEpoch < masterEpoch {
		return nil, errors.New("token revoked due to master key rotation")
	}

	return &TokenInfo{
		MasterID:      uint(masterID),
		IssuedAtEpoch: issuedAtEpoch,
		Status:        tokenData["status"],
		Group:         tokenData["group"],
	}, nil
}
