package handler

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"xboard-go/internal/database"
	"xboard-go/internal/model"
	"xboard-go/internal/service"

	"github.com/gin-gonic/gin"
)

// AdminConfigFetch returns modular configuration settings based on Categories.
// This matches the official Xboard ConfigController.fetch logic.
func AdminConfigFetch(c *gin.Context) {
	key := c.Query("key")
	mappings := getAllConfigMappings()

	if key != "" {
		if val, ok := mappings[key]; ok {
			Success(c, gin.H{key: val})
			return
		}
	}

	Success(c, mappings)
}

// AdminConfigSave saves configuration settings.
func AdminConfigSave(c *gin.Context) {
	var payload map[string]any
	if err := c.ShouldBindJSON(&payload); err != nil {
		Fail(c, http.StatusBadRequest, "invalid request body")
		return
	}

	// In a real implementation, we'd loop through payload and update model.Setting
	// We also handle special keys like subscribe_template_* or frontend_theme
	for k, v := range payload {
		// Special handling for templates could go here
		saveSetting(k, v)
	}

	Success(c, true)
}

func AdminTestSendMail(c *gin.Context) {
	config := service.LoadEmailConfig()
	recipient := currentAdminEmail(c)
	if recipient == "" {
		recipient = config.SenderAddress()
	}

	subject := fmt.Sprintf("[%s] SMTP test email", service.MustGetString("app_name", "XBoard"))
	result := gin.H{
		"email":         recipient,
		"subject":       subject,
		"template_name": config.TemplateName,
		"config":        config.DebugConfig(),
	}

	if recipient == "" {
		result["error"] = "no test recipient is available"
		Success(c, result)
		return
	}

	textBody := strings.Join([]string{
		"This is a test email from SingBox-Gopanel.",
		"",
		"If you received this email, the current SMTP configuration is working.",
	}, "\n")
	htmlBody := strings.Join([]string{
		"<h2>SMTP test email</h2>",
		"<p>If you received this email, the current SMTP configuration is working.</p>",
	}, "")

	if err := service.SendMail(config, service.EmailMessage{
		To:       []string{recipient},
		Subject:  subject,
		TextBody: textBody,
		HTMLBody: htmlBody,
	}); err != nil {
		result["error"] = err.Error()
	}

	Success(c, result)
}

func AdminSetTelegramWebhook(c *gin.Context) {
	SuccessMessage(c, "telegram webhook setup is not wired in the Go backend yet", true)
}

// AdminGetEmailTemplate list available email templates.
func AdminGetEmailTemplate(c *gin.Context) {
	Success(c, collectEmailTemplateNames())
}

// AdminGetThemeTemplate list available themes.
func AdminGetThemeTemplate(c *gin.Context) {
	path := filepath.Join("public", "theme")
	files, err := listDirectoryEntries(path)
	if err != nil {
		Success(c, []string{})
		return
	}
	Success(c, files)
}

func getAllConfigMappings() gin.H {
	return gin.H{
		"invite": gin.H{
			"invite_force":                   service.MustGetBool("invite_force", false),
			"invite_commission":              service.MustGetInt("invite_commission", 10),
			"invite_gen_limit":               service.MustGetInt("invite_gen_limit", 5),
			"invite_never_expire":            service.MustGetBool("invite_never_expire", false),
			"commission_first_time_enable":   service.MustGetBool("commission_first_time_enable", true),
			"commission_auto_check_enable":   service.MustGetBool("commission_auto_check_enable", true),
			"commission_withdraw_limit":      service.MustGetInt("commission_withdraw_limit", 100),
			"commission_withdraw_method":     service.MustGetString("commission_withdraw_method", "alipay"),
			"withdraw_close_enable":          service.MustGetBool("withdraw_close_enable", false),
			"commission_distribution_enable": service.MustGetBool("commission_distribution_enable", false),
			"commission_distribution_l1":     service.MustGetInt("commission_distribution_l1", 0),
			"commission_distribution_l2":     service.MustGetInt("commission_distribution_l2", 0),
			"commission_distribution_l3":     service.MustGetInt("commission_distribution_l3", 0),
		},
		"site": gin.H{
			"logo":                   service.MustGetString("logo", ""),
			"force_https":            service.MustGetInt("force_https", 0),
			"stop_register":          service.MustGetInt("stop_register", 0),
			"app_name":               service.MustGetString("app_name", "XBoard"),
			"app_description":        service.MustGetString("app_description", "XBoard is best!"),
			"app_url":                service.MustGetString("app_url", ""),
			"subscribe_url":          service.MustGetString("subscribe_url", ""),
			"try_out_plan_id":        service.MustGetInt("try_out_plan_id", 0),
			"try_out_hour":           service.MustGetInt("try_out_hour", 1),
			"tos_url":                service.MustGetString("tos_url", ""),
			"currency":               service.MustGetString("currency", "CNY"),
			"currency_symbol":        service.MustGetString("currency_symbol", "¥"),
			"ticket_must_wait_reply": service.MustGetBool("ticket_must_wait_reply", false),
		},
		"subscribe": gin.H{
			"plan_change_enable":             service.MustGetBool("plan_change_enable", true),
			"reset_traffic_method":           service.MustGetInt("reset_traffic_method", 0),
			"surplus_enable":                 service.MustGetBool("surplus_enable", true),
			"new_order_event_id":             service.MustGetInt("new_order_event_id", 0),
			"renew_order_event_id":           service.MustGetInt("renew_order_event_id", 0),
			"change_order_event_id":          service.MustGetInt("change_order_event_id", 0),
			"show_info_to_server_enable":     service.MustGetBool("show_info_to_server_enable", false),
			"show_protocol_to_server_enable": service.MustGetBool("show_protocol_to_server_enable", false),
			"default_remind_expire":          service.MustGetBool("default_remind_expire", true),
			"default_remind_traffic":         service.MustGetBool("default_remind_traffic", true),
			"subscribe_path":                 service.GetSubscribePath(),
		},
		"subscribe_template": service.GetAllSubscribeTemplates(),
		"frontend": gin.H{
			"frontend_theme":          service.MustGetString("frontend_theme", "Xboard"),
			"frontend_theme_sidebar":  service.MustGetString("frontend_theme_sidebar", "light"),
			"frontend_theme_header":   service.MustGetString("frontend_theme_header", "dark"),
			"frontend_theme_color":    service.MustGetString("frontend_theme_color", "default"),
			"frontend_background_url": service.MustGetString("frontend_background_url", ""),
		},
		"server": gin.H{
			"server_token":         service.MustGetString("server_token", ""),
			"server_pull_interval": service.MustGetInt("server_pull_interval", 60),
			"server_push_interval": service.MustGetInt("server_push_interval", 60),
			"device_limit_mode":    service.MustGetInt("device_limit_mode", 0),
			"server_ws_enable":     service.MustGetBool("server_ws_enable", true),
			"server_ws_url":        service.MustGetString("server_ws_url", ""),
		},
		"safe": gin.H{
			"email_verify":                service.MustGetBool("email_verify", false),
			"safe_mode_enable":            service.MustGetBool("safe_mode_enable", false),
			"secure_path":                 service.GetAdminSecurePath(),
			"email_whitelist_enable":      service.MustGetBool("email_whitelist_enable", false),
			"email_whitelist_suffix":      service.MustGetString("email_whitelist_suffix", ""),
			"email_gmail_limit_enable":    service.MustGetBool("email_gmail_limit_enable", false),
			"captcha_enable":              service.MustGetBool("captcha_enable", false),
			"captcha_type":                service.MustGetString("captcha_type", "recaptcha"),
			"register_limit_by_ip_enable": service.MustGetBool("register_limit_by_ip_enable", false),
			"register_limit_count":        service.MustGetInt("register_limit_count", 3),
			"password_limit_enable":       service.MustGetBool("password_limit_enable", true),
		},
		"email": gin.H{
			"email_template":     service.MustGetString("email_template", "classic"),
			"email_host":         service.MustGetString("email_host", ""),
			"email_port":         service.MustGetInt("email_port", 465),
			"email_username":     service.MustGetString("email_username", ""),
			"email_password":     service.MustGetString("email_password", ""),
			"email_encryption":   service.MustGetString("email_encryption", ""),
			"email_from_address": service.LoadEmailConfig().SenderAddress(),
			"email_from_name":    service.MustGetString("email_from_name", service.MustGetString("app_name", "XBoard")),
			"remind_mail_enable": service.MustGetBool("remind_mail_enable", false),
		},
		"nebula": gin.H{
			"nebula_theme_color":        service.MustGetString("nebula_theme_color", "aurora"),
			"nebula_hero_slogan":        service.MustGetString("nebula_hero_slogan", ""),
			"nebula_welcome_target":     service.MustGetString("nebula_welcome_target", ""),
			"nebula_register_title":     service.MustGetString("nebula_register_title", ""),
			"nebula_background_url":     service.MustGetString("nebula_background_url", ""),
			"nebula_metrics_base_url":   service.MustGetString("nebula_metrics_base_url", ""),
			"nebula_default_theme_mode": service.MustGetString("nebula_default_theme_mode", "system"),
			"nebula_light_logo_url":     service.MustGetString("nebula_light_logo_url", ""),
			"nebula_dark_logo_url":      service.MustGetString("nebula_dark_logo_url", ""),
			"nebula_custom_html":        service.MustGetString("nebula_custom_html", ""),
			"nebula_static_cdn_url":     service.MustGetString("nebula_static_cdn_url", ""),
		},
	}
}

func saveSetting(name string, value any) {
	var val string
	switch v := value.(type) {
	case string:
		val = v
	case int:
		val = strconv.Itoa(v)
	case int64:
		val = strconv.FormatInt(v, 10)
	case float64:
		val = strconv.FormatFloat(v, 'f', -1, 64)
	case bool:
		if v {
			val = "1"
		} else {
			val = "0"
		}
	default:
		// serialize complex types if needed
	}

	result := database.DB.Model(&model.Setting{}).Where("name = ?", name).Update("value", val)
	if result.Error == nil && result.RowsAffected > 0 {
		return
	}

	setting := model.Setting{
		Name:  name,
		Value: val,
	}
	if group := settingGroupName(name); group != "" {
		setting.Group = &group
	}
	_ = database.DB.Where("name = ?", name).FirstOrCreate(&setting).Error
}

func listDirectoryEntries(dir string) ([]string, error) {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return nil, err
	}
	var files []string
	for _, entry := range entries {
		files = append(files, entry.Name())
	}
	return files, nil
}

func collectEmailTemplateNames() []string {
	names := map[string]struct{}{
		"classic": {},
	}

	candidates := []string{
		filepath.Join("resource", "views", "mail"),
		filepath.Join("reference", "Xboard", "resources", "views", "mail"),
	}

	for _, dir := range candidates {
		entries, err := listDirectoryEntries(dir)
		if err != nil {
			continue
		}
		for _, entry := range entries {
			entry = strings.TrimSpace(entry)
			if entry == "" {
				continue
			}
			names[entry] = struct{}{}
		}
	}

	result := make([]string, 0, len(names))
	for name := range names {
		result = append(result, name)
	}
	sort.Strings(result)
	return result
}

func currentAdminEmail(c *gin.Context) string {
	userID, exists := c.Get("user_id")
	if !exists {
		return ""
	}

	var user model.User
	if err := database.DB.Select("email").Where("id = ?", intFromAny(userID)).First(&user).Error; err != nil {
		return ""
	}
	return strings.TrimSpace(user.Email)
}

func settingGroupName(name string) string {
	switch name {
	case "invite_force", "invite_commission", "invite_gen_limit", "invite_never_expire",
		"commission_first_time_enable", "commission_auto_check_enable", "commission_withdraw_limit",
		"commission_withdraw_method", "withdraw_close_enable", "commission_distribution_enable",
		"commission_distribution_l1", "commission_distribution_l2", "commission_distribution_l3":
		return "invite"
	case "logo", "force_https", "stop_register", "app_name", "app_description", "app_url",
		"subscribe_url", "try_out_plan_id", "try_out_hour", "tos_url", "currency",
		"currency_symbol", "ticket_must_wait_reply":
		return "site"
	case "plan_change_enable", "reset_traffic_method", "surplus_enable", "new_order_event_id",
		"renew_order_event_id", "change_order_event_id", "show_info_to_server_enable",
		"show_protocol_to_server_enable", "default_remind_expire", "default_remind_traffic", "subscribe_path":
		return "subscribe"
	case "subscribe_template_singbox", "subscribe_template_clash", "subscribe_template_clashmeta",
		"subscribe_template_stash", "subscribe_template_surge", "subscribe_template_surfboard":
		return "subscribe_template"
	case "frontend_theme", "frontend_theme_sidebar", "frontend_theme_header", "frontend_theme_color", "frontend_background_url":
		return "frontend"
	case "server_token", "server_pull_interval", "server_push_interval", "device_limit_mode", "server_ws_enable", "server_ws_url":
		return "server"
	case "email_verify", "safe_mode_enable", "secure_path", "email_whitelist_enable",
		"email_whitelist_suffix", "email_gmail_limit_enable", "captcha_enable", "captcha_type",
		"register_limit_by_ip_enable", "register_limit_count", "password_limit_enable":
		return "safe"
	case "email_template", "email_host", "email_port", "email_username", "email_password", "email_encryption",
		"email_from_address", "email_from_name", "email_from", "remind_mail_enable":
		return "email"
	case "nebula_theme_color", "nebula_hero_slogan", "nebula_welcome_target", "nebula_register_title",
		"nebula_background_url", "nebula_metrics_base_url", "nebula_default_theme_mode",
		"nebula_light_logo_url", "nebula_dark_logo_url", "nebula_custom_html", "nebula_static_cdn_url":
		return "nebula"
	default:
		return ""
	}
}
