package authentik

import (
	"fmt"
	"strings"

	"github.com/ultisuite/ulti-backend/internal/config"
)

const suiteGroup = "Ulti Suite"

// AppSpec describes one Authentik OAuth application to provision when enabled.
type AppSpec struct {
	Key          string
	Slug         string
	ProviderName string
	DisplayName  string
	ClientID     func(*config.Config) string
	ClientSecret func(*config.Config) string
	LaunchURL    func(*config.Config) string
	RedirectURIs func(*config.Config) []string
	Enabled      func(*config.Config) bool
	OfflineAccess bool
}

func baseURL(cfg *config.Config) string {
	host := strings.TrimSpace(cfg.Domain)
	if host == "" {
		host = "localhost"
	}
	scheme := "http"
	if cfg.AuthentikPublicHTTPS {
		scheme = "https"
	}
	return fmt.Sprintf("%s://%s", scheme, host)
}

func Catalog(cfg *config.Config) []AppSpec {
	return []AppSpec{
		{
			Key:          "ultimail",
			Slug:         "ulti",
			ProviderName: "ulti-backend-provider",
			DisplayName:  "Ultimail",
			ClientID:     func(c *config.Config) string { return c.OIDCClientID },
			ClientSecret: func(c *config.Config) string { return c.OIDCClientSecret },
			LaunchURL:    func(c *config.Config) string { return c.MailAppURL + "/" },
			RedirectURIs: ultimailRedirectURIs,
			Enabled:      func(c *config.Config) bool { return c.OIDCClientID != "" && c.OIDCClientSecret != "" },
			OfflineAccess: true,
		},
		{
			Key:          "nextcloud",
			Slug:         "nextcloud",
			ProviderName: "ulti-nextcloud-provider",
			DisplayName:  "Nextcloud",
			ClientID:     func(c *config.Config) string { return c.NCOIDCClientID },
			ClientSecret: func(c *config.Config) string { return c.NCOIDCClientSecret },
			LaunchURL:    func(c *config.Config) string { return baseURL(c) + "/cloud/" },
			RedirectURIs: nextcloudRedirectURIs,
			Enabled:      func(c *config.Config) bool { return c.NextcloudEnabled },
		},
		{
			Key:          "onlyoffice",
			Slug:         "onlyoffice",
			ProviderName: "ulti-onlyoffice-provider",
			DisplayName:  "OnlyOffice",
			ClientID:     func(c *config.Config) string { return c.OnlyOfficeOIDCClientID },
			ClientSecret: func(c *config.Config) string { return c.OnlyOfficeOIDCClientSecret },
			LaunchURL:    func(c *config.Config) string { return c.OnlyOfficePublicURL },
			RedirectURIs: onlyofficeRedirectURIs,
			Enabled:      func(c *config.Config) bool { return c.OnlyOfficeEnabled },
		},
		{
			Key:          "immich",
			Slug:         "immich",
			ProviderName: "ulti-immich-provider",
			DisplayName:  "Ultiphotos",
			ClientID:     func(c *config.Config) string { return c.ImmichOIDCClientID },
			ClientSecret: func(c *config.Config) string { return c.ImmichOIDCClientSecret },
			LaunchURL:    func(c *config.Config) string { return baseURL(c) + "/photos/" },
			RedirectURIs: immichRedirectURIs,
			Enabled:      func(c *config.Config) bool { return c.ImmichEnabled },
		},
		{
			Key:          "ultidrive",
			Slug:         "ultidrive",
			ProviderName: "ulti-drive-provider",
			DisplayName:  "UltiDrive",
			ClientID:     func(c *config.Config) string { return c.DriveOIDCClientID },
			ClientSecret: func(c *config.Config) string { return c.DriveOIDCClientSecret },
			LaunchURL:    func(c *config.Config) string { return baseURL(c) + "/drive/" },
			RedirectURIs: driveRedirectURIs,
			Enabled: func(c *config.Config) bool {
				return c.NextcloudEnabled && c.DriveOIDCClientID != ""
			},
		},
	}
}

func ultimailRedirectURIs(cfg *config.Config) []string {
	base := baseURL(cfg)
	mail := strings.TrimRight(cfg.MailAppURL, "/")
	return uniqueURIs(
		mail+"/api/auth/callback",
		"http://localhost:3000/api/auth/callback",
		"http://127.0.0.1:3000/api/auth/callback",
		base+"/api/auth/callback",
	)
}

func nextcloudRedirectURIs(cfg *config.Config) []string {
	base := baseURL(cfg)
	return uniqueURIs(
		base+"/cloud/apps/user_oidc/code",
		"http://localhost/cloud/apps/user_oidc/code",
		"http://127.0.0.1/cloud/apps/user_oidc/code",
	)
}

func onlyofficeRedirectURIs(cfg *config.Config) []string {
	base := baseURL(cfg)
	office := strings.TrimRight(cfg.OnlyOfficePublicURL, "/")
	return uniqueURIs(
		office+"/",
		office+"/oauth2/callback",
		base+"/office/",
		base+"/office/oauth2/callback",
		"http://localhost/office/",
	)
}

func immichRedirectURIs(cfg *config.Config) []string {
	base := baseURL(cfg)
	return uniqueURIs(
		base+"/photos/auth/login",
		base+"/photos/user-settings",
		"http://localhost/photos/auth/login",
	)
}

func driveRedirectURIs(cfg *config.Config) []string {
	base := baseURL(cfg)
	return uniqueURIs(
		base+"/api/auth/callback",
		"http://localhost:3000/api/auth/callback",
		"http://127.0.0.1:3000/api/auth/callback",
	)
}

func uniqueURIs(uris ...string) []string {
	seen := map[string]struct{}{}
	var out []string
	for _, u := range uris {
		u = strings.TrimSpace(u)
		if u == "" {
			continue
		}
		if _, ok := seen[u]; ok {
			continue
		}
		seen[u] = struct{}{}
		out = append(out, u)
	}
	return out
}
