package repo

import (
	"context"
	"sort"
	"strings"
	"time"

	"backend/internal/model"
	"gorm.io/gorm"
)

type ShowcaseRepository struct {
	db *gorm.DB
}

func NewShowcaseRepository(db *gorm.DB) *ShowcaseRepository {
	return &ShowcaseRepository{db: db}
}

func (r *ShowcaseRepository) IsPublicFile(ctx context.Context, rel string) (bool, error) {
	normalized := strings.TrimLeft(strings.TrimSpace(rel), "/")
	if normalized == "" {
		return false, nil
	}

	var count int64
	if err := r.db.WithContext(ctx).
		Model(&model.ShowcaseItem{}).
		Where("image = ? OR image = ?", normalized, "/"+normalized).
		Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}

// PublicFileSet returns the set of image keys referenced by any showcase item
// (normalized, no leading slash). The media-prune sweep uses it to never delete
// a file the homepage still shows, regardless of how old the file is.
func (r *ShowcaseRepository) PublicFileSet(ctx context.Context) (map[string]struct{}, error) {
	var images []string
	if err := r.db.WithContext(ctx).
		Model(&model.ShowcaseItem{}).
		Where("image <> ''").
		Pluck("image", &images).Error; err != nil {
		return nil, err
	}
	set := make(map[string]struct{}, len(images))
	for _, img := range images {
		n := strings.TrimLeft(strings.TrimSpace(img), "/")
		if n != "" {
			set[n] = struct{}{}
		}
	}
	return set, nil
}

func (r *ShowcaseRepository) Grouped(ctx context.Context) (map[string][]model.ShowcaseItem, error) {
	var items []model.ShowcaseItem
	if err := r.db.WithContext(ctx).Find(&items).Error; err != nil {
		return nil, err
	}

	grouped := map[string][]model.ShowcaseItem{
		"hero":  {},
		"bento": {},
		"work":  {},
	}
	for _, item := range items {
		grouped[item.Kind] = append(grouped[item.Kind], item)
	}
	for kind := range grouped {
		sort.Slice(grouped[kind], func(i, j int) bool {
			return grouped[kind][i].Weight > grouped[kind][j].Weight
		})
	}
	return grouped, nil
}

func (r *ShowcaseRepository) Create(ctx context.Context, item *model.ShowcaseItem) error {
	return r.db.WithContext(ctx).Create(item).Error
}

func (r *ShowcaseRepository) Update(ctx context.Context, entryID string, patch map[string]any) (*model.ShowcaseItem, error) {
	patch["updated_at"] = time.Now()
	if err := r.db.WithContext(ctx).Model(&model.ShowcaseItem{}).Where("id = ?", entryID).Updates(patch).Error; err != nil {
		return nil, err
	}
	var item model.ShowcaseItem
	if err := r.db.WithContext(ctx).First(&item, "id = ?", entryID).Error; err != nil {
		return nil, err
	}
	return &item, nil
}

func (r *ShowcaseRepository) Delete(ctx context.Context, entryID string) (int64, error) {
	res := r.db.WithContext(ctx).Delete(&model.ShowcaseItem{}, "id = ?", entryID)
	return res.RowsAffected, res.Error
}
