package user

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"sync"
	"time"

	"crussell/db"
	"crussell/clock"
	"crussell/mw"
)

var (
	gdprExportCache   = make(map[string]*gdprCacheEntry)
	gdprExportCacheMu sync.RWMutex
)

type gdprCacheEntry struct {
	data       json.RawMessage
	expiresAt  time.Time
	generating bool
}

// CleanupGDPRExportCache removes expired entries from the GDPR export cache.
// Called by the centralised jobs scheduler.
func CleanupGDPRExportCache(ctx context.Context) (int, error) {
	gdprExportCacheMu.Lock()
	defer gdprExportCacheMu.Unlock()
	now := clock.Now()
	var n int
	for k, v := range gdprExportCache {
		if now.After(v.expiresAt) {
			delete(gdprExportCache, k)
			n++
		}
	}
	return n, nil
}

// GET /api/user/gdpr-export
func GetGDPRExportHandler(w http.ResponseWriter, r *http.Request) {
	userID, ok := mw.GetUserID(r.Context())
	if !ok {
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	}

	gdprExportCacheMu.Lock()
	if entry, found := gdprExportCache[userID]; found && clock.Now().Before(entry.expiresAt) {
		if entry.generating {
			gdprExportCacheMu.Unlock()
			w.Header().Set("X-Cache", "GENERATING")
			_, _ = w.Write([]byte(`{"status":"generating"}`))
			return
		}
		gdprExportCacheMu.Unlock()
		w.Header().Set("X-Cache", "HIT")
		_, _ = w.Write(entry.data)
		return
	}

	gdprExportCache[userID] = &gdprCacheEntry{generating: true}
	gdprExportCacheMu.Unlock()

	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("Panic recovered in GDPR export query: %v", r)
			}
		}()
		var result json.RawMessage
		err := db.Conn.QueryRow(context.Background(), `SELECT export_all_user_data($1)`, userID).Scan(&result)
		if err != nil {
			log.Printf("GDPR export failed for user %s: %v", userID, err)
			gdprExportCacheMu.Lock()
			delete(gdprExportCache, userID)
			gdprExportCacheMu.Unlock()
			return
		}

		gdprExportCacheMu.Lock()
		gdprExportCache[userID] = &gdprCacheEntry{
			data:      result,
			expiresAt: clock.Now().Add(12 * time.Hour),
		}
		gdprExportCacheMu.Unlock()
	}()

	w.Header().Set("X-Cache", "MISS")
	_, _ = w.Write([]byte(`{"status":"generating"}`))
}
