package registry

import (
	"sort"
	"strings"
)

const (
	GitHubAppID                  = "app_github"
	GitHubAppSlug                = "github"
	GiteaAppID                   = "app_gitea"
	GiteaAppSlug                 = "gitea"
	EmailAppID                   = "app_email"
	EmailAppSlug                 = "email"
	SearXNGAppID                 = "app_searxng"
	SearXNGAppSlug               = "searxng"
	BraveSearchAppID             = "app_brave_search"
	BraveSearchAppSlug           = "brave"
	TavilyAppID                  = "app_tavily"
	TavilyAppSlug                = "tavily"
	SerperAppID                  = "app_serper"
	SerperAppSlug                = "serper"
	ArxivAppID                   = "app_arxiv"
	ArxivAppSlug                 = "arxiv"
	TodoistAppID                 = "app_todoist"
	TodoistAppSlug               = "todoist"
	NotionAppID                  = "app_notion"
	NotionAppSlug                = "notion"
	HackernewsAppID              = "app_hackernews"
	HackernewsAppSlug            = "hackernews"
	JenkinsAppID                 = "app_jenkins"
	JenkinsAppSlug               = "jenkins"
	OnesAppID                    = "app_ones"
	OnesAppSlug                  = "ones"
	HotNewsAppID                 = "app_hotnews"
	HotNewsAppSlug               = "hotnews"
	FeishuCustomBotAppID         = "app_feishu_custom_bot"
	FeishuCustomBotAppSlug       = "feishucustombot"
	DingtalkBotAppID             = "app_dingtalk_bot"
	DingtalkBotAppSlug           = "dingtalkbot"
	WecomBotAppID                = "app_wecom_bot"
	WecomBotAppSlug              = "wecombot"
	TianyanchaAppID              = "app_tianyancha"
	TianyanchaAppSlug            = "tianyancha"
	QichachaAppID                = "app_qichacha"
	QichachaAppSlug              = "qichacha"
	TushareAppID                 = "app_tushare"
	TushareAppSlug               = "tushare"
	AlphaVantageAppID            = "app_alpha_vantage"
	AlphaVantageAppSlug          = "alpha-vantage"
	FinancialModelingPrepAppID   = "app_financial_modeling_prep"
	FinancialModelingPrepAppSlug = "financial-modeling-prep"
	Jin10AppID                   = "app_jin10"
	Jin10AppSlug                 = "jin10"
	PKULawAppID                  = "app_pkulaw"
	PKULawAppSlug                = "pkulaw"
	AIFinMarketAppID             = "app_aifinmarket"
	AIFinMarketAppSlug           = "aifinmarket"
)

var productAppSlugsByID = map[string]string{
	GitHubAppID:                GitHubAppSlug,
	GiteaAppID:                 GiteaAppSlug,
	EmailAppID:                 EmailAppSlug,
	SearXNGAppID:               SearXNGAppSlug,
	BraveSearchAppID:           BraveSearchAppSlug,
	TavilyAppID:                TavilyAppSlug,
	SerperAppID:                SerperAppSlug,
	ArxivAppID:                 ArxivAppSlug,
	TodoistAppID:               TodoistAppSlug,
	NotionAppID:                NotionAppSlug,
	HackernewsAppID:            HackernewsAppSlug,
	JenkinsAppID:               JenkinsAppSlug,
	OnesAppID:                  OnesAppSlug,
	HotNewsAppID:               HotNewsAppSlug,
	FeishuCustomBotAppID:       FeishuCustomBotAppSlug,
	DingtalkBotAppID:           DingtalkBotAppSlug,
	WecomBotAppID:              WecomBotAppSlug,
	TianyanchaAppID:            TianyanchaAppSlug,
	QichachaAppID:              QichachaAppSlug,
	TushareAppID:               TushareAppSlug,
	AlphaVantageAppID:          AlphaVantageAppSlug,
	FinancialModelingPrepAppID: FinancialModelingPrepAppSlug,
	Jin10AppID:                 Jin10AppSlug,
	PKULawAppID:                PKULawAppSlug,
	AIFinMarketAppID:           AIFinMarketAppSlug,
}

// ProductAppSlugs returns the slug of every product App AgentTeam currently
// exposes, sorted for stable test expectations. Visibility fixtures derive
// their expected catalog from this single registration source instead of
// maintaining a second hand-copied list.
func ProductAppSlugs() []string {
	slugs := make([]string, 0, len(productAppSlugsByID))
	for _, slug := range productAppSlugsByID {
		slugs = append(slugs, slug)
	}
	sort.Strings(slugs)
	return slugs
}

// IsProductApp reports whether an App registry identity belongs to an App that
// AgentTeam currently exposes and executes. The App product surface is deliberately
// closed: custom/developer Apps no longer have a runtime or an authoring API.
func IsProductApp(appID string, appSlug string) bool {
	id := strings.TrimSpace(appID)
	slug := strings.ToLower(strings.TrimSpace(appSlug))
	expectedSlug, ok := productAppSlugsByID[id]
	return ok && slug == expectedSlug
}

// IsProductAppID is the ID-only variant used after an immutable definition has
// already been resolved.
func IsProductAppID(appID string) bool {
	_, ok := productAppSlugsByID[strings.TrimSpace(appID)]
	return ok
}

// IsProductAppSlug reports whether a slug is handled by the retained provider
// App implementations.
func IsProductAppSlug(appSlug string) bool {
	slug := strings.ToLower(strings.TrimSpace(appSlug))
	for _, productSlug := range productAppSlugsByID {
		if slug == productSlug {
			return true
		}
	}
	return false
}

// SupportedExternalMentionRuntimeCapability validates a stored, pinned manifest
// against the same narrow contract used by workspace App onboarding. Returning
// false is intentionally fail-closed: legacy custom Apps, malformed manifests,
// notification-only Apps, and hand-written mention declarations without the
// required runtime/scopes must never become catalog or installation entries.
func SupportedExternalMentionRuntimeCapability(appSlug string, appKind string, manifestJSON []byte) (StoredAppRuntimeCapability, bool) {
	if strings.TrimSpace(appKind) != "third_party" {
		return StoredAppRuntimeCapability{}, false
	}
	validated, err := ValidateDeveloperManifest(appSlug, appKind, manifestJSON)
	if err != nil {
		return StoredAppRuntimeCapability{}, false
	}
	capability, err := ParseStoredAppRuntimeCapability(validated.Payload)
	if err != nil || !capability.Supported || !containsString(capability.Events, AppEventMessageMention) {
		return StoredAppRuntimeCapability{}, false
	}
	return capability, true
}
