// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package webtheme

import (
	"sort"
	"strings"
	"sync"

	"code.gitea.io/gitea/modules/container"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/public"
	"code.gitea.io/gitea/modules/setting"
)

var (
	availableThemes    []string
	availableThemesSet container.Set[string]
	themeOnce          sync.Once
)

func initThemes() {
	availableThemes = nil
	defer func() {
		availableThemesSet = container.SetOf(availableThemes...)
		if !availableThemesSet.Contains(setting.UI.DefaultTheme) {
			setting.LogStartupProblem(1, log.ERROR, "Default theme %q is not available, please correct the '[ui].DEFAULT_THEME' setting in the config file", setting.UI.DefaultTheme)
		}
	}()
	cssFiles, err := public.AssetFS().ListFiles("/assets/css")
	if err != nil {
		log.Error("Failed to list themes: %v", err)
		availableThemes = []string{setting.UI.DefaultTheme}
		return
	}
	var foundThemes []string
	for _, name := range cssFiles {
		name, ok := strings.CutPrefix(name, "theme-")
		if !ok {
			continue
		}
		name, ok = strings.CutSuffix(name, ".css")
		if !ok {
			continue
		}
		foundThemes = append(foundThemes, name)
	}
	if len(setting.UI.Themes) > 0 {
		allowedThemes := container.SetOf(setting.UI.Themes...)
		for _, theme := range foundThemes {
			if allowedThemes.Contains(theme) {
				availableThemes = append(availableThemes, theme)
			}
		}
	} else {
		availableThemes = foundThemes
	}
	sort.Strings(availableThemes)
	if len(availableThemes) == 0 {
		setting.LogStartupProblem(1, log.ERROR, "No theme candidate in asset files, but Gitea requires there should be at least one usable theme")
		availableThemes = []string{setting.UI.DefaultTheme}
	}
}

func GetAvailableThemes() []string {
	themeOnce.Do(initThemes)
	return availableThemes
}

func IsThemeAvailable(name string) bool {
	themeOnce.Do(initThemes)
	return availableThemesSet.Contains(name)
}