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

package setting

import (
	"time"

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

// UI settings
var UI = struct {
	ExplorePagingNum        int
	SitemapPagingNum        int
	IssuePagingNum          int
	RepoSearchPagingNum     int
	MembersPagingNum        int
	FeedMaxCommitNum        int
	FeedPagingNum           int
	PackagesPagingNum       int
	GraphMaxCommitNum       int
	CodeCommentLines        int
	ReactionMaxUserNum      int
	MaxDisplayFileSize      int64
	ShowUserEmail           bool
	DefaultTheme            string
	Themes                  []string
	FileIconTheme           string
	FolderIconTheme         string
	Reactions               []string
	ReactionsLookup         container.Set[string] `ini:"-"`
	CustomEmojis            []string
	CustomEmojisMap         map[string]string `ini:"-"`
	EnabledEmojis           []string
	EnabledEmojisSet        container.Set[string] `ini:"-"`
	SearchRepoDescription   bool
	OnlyShowRelevantRepos   bool
	ExploreDefaultSort      string `ini:"EXPLORE_PAGING_DEFAULT_SORT"`
	PreferredTimestampTense string

	AmbiguousUnicodeDetection bool

	// TODO: DefaultShowFullName is introduced by https://github.com/go-gitea/gitea/pull/6710
	// But there are still many edge cases:
	// * Many places still use "username", not respecting this setting
	// * Many places use "Full Name" if it is not empty, cause inconsistent UI for users who have set their full name but some others don't
	// * Even if DefaultShowFullName=false, many places still need to show the full name
	// For most cases, either "username" or "username (Full Name)" should be used and are good enough.
	// Only in very few cases (e.g.: unimportant lists, narrow layout), "username" or "Full Name" can be used.
	DefaultShowFullName bool

	Notification struct {
		MinTimeout            time.Duration
		TimeoutStep           time.Duration
		MaxTimeout            time.Duration
		EventSourceUpdateTime time.Duration
	} `ini:"ui.notification"`

	SVG struct {
		Enabled bool `ini:"ENABLE_RENDER"`
	} `ini:"ui.svg"`

	CSV struct {
		MaxFileSize int64
		MaxRows     int
	} `ini:"ui.csv"`

	Admin struct {
		UserPagingNum   int
		RepoPagingNum   int
		NoticePagingNum int
		OrgPagingNum    int
	} `ini:"ui.admin"`
	User struct {
		RepoPagingNum int
		OrgPagingNum  int
	} `ini:"ui.user"`
	Meta struct {
		Author      string
		Description string
		Keywords    string
	} `ini:"ui.meta"`
}{
	ExplorePagingNum:        20,
	SitemapPagingNum:        20,
	IssuePagingNum:          20,
	RepoSearchPagingNum:     20,
	MembersPagingNum:        20,
	FeedMaxCommitNum:        5,
	FeedPagingNum:           20,
	PackagesPagingNum:       20,
	GraphMaxCommitNum:       100,
	CodeCommentLines:        4,
	ReactionMaxUserNum:      10,
	MaxDisplayFileSize:      8388608,
	DefaultTheme:            `gitea-auto`,
	FileIconTheme:           `material`,
	FolderIconTheme:         `basic`,
	Reactions:               []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
	CustomEmojis:            []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
	CustomEmojisMap:         map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
	ExploreDefaultSort:      "recentupdate",
	PreferredTimestampTense: "mixed",

	AmbiguousUnicodeDetection: true,

	Notification: struct {
		MinTimeout            time.Duration
		TimeoutStep           time.Duration
		MaxTimeout            time.Duration
		EventSourceUpdateTime time.Duration
	}{
		MinTimeout:            10 * time.Second,
		TimeoutStep:           10 * time.Second,
		MaxTimeout:            60 * time.Second,
		EventSourceUpdateTime: 10 * time.Second,
	},
	SVG: struct {
		Enabled bool `ini:"ENABLE_RENDER"`
	}{
		Enabled: true,
	},
	CSV: struct {
		MaxFileSize int64
		MaxRows     int
	}{
		MaxFileSize: 524288,
		MaxRows:     2500,
	},
	Admin: struct {
		UserPagingNum   int
		RepoPagingNum   int
		NoticePagingNum int
		OrgPagingNum    int
	}{
		UserPagingNum:   50,
		RepoPagingNum:   50,
		NoticePagingNum: 25,
		OrgPagingNum:    50,
	},
	User: struct {
		RepoPagingNum int
		OrgPagingNum  int
	}{
		RepoPagingNum: 15,
		OrgPagingNum:  15,
	},
	Meta: struct {
		Author      string
		Description string
		Keywords    string
	}{
		Author:      "Gitea - Git with a cup of tea",
		Description: "Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go",
		Keywords:    "go,git,self-hosted,gitea",
	},
}

func loadUIFrom(rootCfg ConfigProvider) {
	mustMapSetting(rootCfg, "ui", &UI)
	sec := rootCfg.Section("ui")
	UI.ShowUserEmail = sec.Key("SHOW_USER_EMAIL").MustBool(true)
	UI.DefaultShowFullName = sec.Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
	UI.SearchRepoDescription = sec.Key("SEARCH_REPO_DESCRIPTION").MustBool(true)

	if UI.PreferredTimestampTense != "mixed" && UI.PreferredTimestampTense != "absolute" {
		log.Fatal("ui.PREFERRED_TIMESTAMP_TENSE must be either 'mixed' or 'absolute'")
	}

	// OnlyShowRelevantRepos=false is important for many private/enterprise instances,
	// because many private repositories do not have "description/topic", users just want to search by their names.
	UI.OnlyShowRelevantRepos = sec.Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false)

	UI.ReactionsLookup = make(container.Set[string])
	for _, reaction := range UI.Reactions {
		UI.ReactionsLookup.Add(reaction)
	}
	UI.CustomEmojisMap = make(map[string]string)
	for _, emoji := range UI.CustomEmojis {
		UI.CustomEmojisMap[emoji] = ":" + emoji + ":"
	}
	UI.EnabledEmojisSet = container.SetOf(UI.EnabledEmojis...)
}
