package contests

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

	"cloud.google.com/go/firestore"
	"github.com/reimage-ai/broker/firebase"
)

const bucketBaseURL = "https://storage.googleapis.com/reimage-assets"
const cacheTTL = 5 * time.Minute

type Contest struct {
	ID            string           `json:"id"            firestore:"-"`
	Name          string           `json:"name"          firestore:"name"`
	Description   string           `json:"description"   firestore:"description"`
	ImageURL      string           `json:"image_url"     firestore:"-"`
	CoverImageURL string           `json:"cover_image_url"     firestore:"-"`
	ImageMD5      string           `json:"image_md5"     firestore:"image_md5"`
	StartDate     time.Time        `json:"start_date"    firestore:"start_date"`
	EndDate       time.Time        `json:"end_date"      firestore:"end_date"`
	Participants  []map[string]any `json:"participants"      firestore:"participants"`

	// Firestore-only fields — not serialized in JSON response.
	ImagePath      string `json:"-" firestore:"image_path"`
	CoverImagePath string `json:"-" firestore:"cover_image_path"`
}

var (
	cache     map[string][]Contest = make(map[string][]Contest)
	cacheTime map[string]time.Time = make(map[string]time.Time)
	cacheMu   sync.RWMutex
)

// GetContests returns active products with thumbnail and image URLs.
func GetContests(app string) ([]Contest, error) {
	client := firebase.FirestoreClientReimage()

	cacheMu.RLock()
	if cache != nil && time.Since(cacheTime[app]) < cacheTTL {
		result := cache[app]
		cacheMu.RUnlock()
		return result, nil
	}
	cacheMu.RUnlock()

	ctx := context.Background()

	now := time.Now().UTC()
	docs, err := client.Collection("contests").Where("start_date", "<", now).Where("app", "==", app).OrderBy("end_date", firestore.Desc).Documents(ctx).GetAll()
	if err != nil {
		// Stale-on-error: return expired cache if available rather than surfacing a 5xx
		cacheMu.RLock()
		stale := cache[app]
		cacheMu.RUnlock()
		if stale != nil {
			log.Printf("Warning: Contests: Firestore error, serving stale cache: %v\n", err)
			return stale, nil
		}
		return nil, err
	}

	contests := make([]Contest, 0, len(docs))
	for _, doc := range docs {
		var c Contest
		if err := doc.DataTo(&c); err != nil {
			log.Printf("Error: Contests: skip bad doc %s: %v\n", doc.Ref.ID, err)
			continue
		}
		c.ID = doc.Ref.ID
		c.ImageURL = bucketBaseURL + "/" + c.ImagePath
		c.CoverImageURL = bucketBaseURL + "/" + c.CoverImagePath
		for _, part := range c.Participants {
			var images = make([]string, 0)
			var imagePaths []any = part["image_paths"].([]any)
			for _, imagePath := range imagePaths {
				imageUrl := fmt.Sprintf("%s/%v", bucketBaseURL, imagePath)
				images = append(images, imageUrl)
			}
			part["images"] = images
		}

		contests = append(contests, c)
	}

	cacheMu.Lock()
	cache[app] = contests
	cacheTime[app] = time.Now()
	cacheMu.Unlock()

	return contests, nil
}

// return a list of image md5s for all running contests
// this is used for entitlement checks
func GetContestMD5s(app string) []string {
	contests, err := GetContests(app)
	if err != nil {
		return []string{}
	}

	var md5s = make([]string, 0)
	now := time.Now().UTC()
	for _, contest := range contests {
		if contest.StartDate.Before(now) && contest.EndDate.After(now) {
			md5s = append(md5s, contest.ImageMD5)
		}
	}
	return md5s
}
