package client

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
)

// DefaultCacheTTL is the default cache duration for purchase code validation (24 hours)
const DefaultCacheTTL = 24 * time.Hour

// cacheEntry stores a cached purchase code validation result
type cacheEntry struct {
	valid     bool
	expiresAt time.Time
}

// TitanClient handles purchase code validation via TitanSystems API
type TitanClient struct {
	httpClient *http.Client
	logger     *logrus.Logger
	baseURL    string // Configurable for testing
	cache      map[string]cacheEntry
	cacheMu    sync.RWMutex
	cacheTTL   time.Duration
}

type titanResponse struct {
	Status int `json:"status"`
}

// NewTitanClient creates a new TitanSystems API client
func NewTitanClient(logger *logrus.Logger) *TitanClient {
	return &TitanClient{
		httpClient: &http.Client{Timeout: 30 * time.Second},
		logger:     logger,
		baseURL:    "https://api.titansystems.ph/appy/verify",
		cache:      make(map[string]cacheEntry),
		cacheTTL:   DefaultCacheTTL,
	}
}

// VerifyPurchaseCode validates a purchase code via TitanSystems API
// Results are cached for 24 hours (both valid and invalid codes)
// Returns true if valid (status 200), false if invalid (status 401)
func (c *TitanClient) VerifyPurchaseCode(code string) (bool, error) {
	logCode := c.truncateCode(code)

	// Check cache first
	if valid, found := c.getFromCache(code); found {
		c.logger.WithFields(logrus.Fields{
			"code":   logCode,
			"cached": true,
		}).Debug("Validating purchase code")
		return valid, nil
	}

	// Cache miss - make API call
	c.logger.WithFields(logrus.Fields{
		"code": logCode,
	}).Debug("Validating purchase code")

	valid, err := c.verifyFromAPI(code)
	if err != nil {
		return false, err
	}

	// Store in cache (both valid and invalid results)
	c.setCache(code, valid)

	c.logger.WithFields(logrus.Fields{
		"valid": valid,
	}).Debug("Purchase code validation result")

	return valid, nil
}

// getFromCache returns the cached result if present and not expired
func (c *TitanClient) getFromCache(code string) (valid bool, found bool) {
	c.cacheMu.RLock()
	defer c.cacheMu.RUnlock()

	entry, exists := c.cache[code]
	if !exists {
		return false, false
	}

	// Check if expired
	if time.Now().After(entry.expiresAt) {
		return false, false
	}

	return entry.valid, true
}

// setCache stores a validation result in the cache
func (c *TitanClient) setCache(code string, valid bool) {
	c.cacheMu.Lock()
	defer c.cacheMu.Unlock()

	c.cache[code] = cacheEntry{
		valid:     valid,
		expiresAt: time.Now().Add(c.cacheTTL),
	}
}

// verifyFromAPI performs the actual API call to TitanSystems
func (c *TitanClient) verifyFromAPI(code string) (bool, error) {
	url := c.baseURL + "?code=" + code

	resp, err := c.httpClient.Get(url)
	if err != nil {
		return false, fmt.Errorf("failed to contact TitanSystems API: %w", err)
	}
	defer resp.Body.Close()

	var result titanResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return false, fmt.Errorf("failed to parse TitanSystems response: %w", err)
	}

	return result.Status == 200, nil
}

// truncateCode returns a truncated version of the code for logging
func (c *TitanClient) truncateCode(code string) string {
	if len(code) > 8 {
		return code[:8] + "..."
	}
	return code
}
