package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"gopkg.in/ini.v1"
)

const (
	defaultPort     = 3000
	defaultDataRel  = "data"
	defaultConfName = "app.ini"
)

// fileSettings 从 app.ini 读出的原始值（尚未解析为绝对路径）
type fileSettings struct {
	Port         int
	DataRel      string
	JWTSecret    string
	CommunityHub bool // 维护者选项：是否作为社区枢纽收报
}

func defaultFileSettings() fileSettings {
	return fileSettings{
		Port:    defaultPort,
		DataRel: defaultDataRel,
	}
}

func loadAppINI(path string) (fileSettings, error) {
	out := defaultFileSettings()
	cfg, err := ini.LoadSources(ini.LoadOptions{
		IgnoreInlineComment: true,
	}, path)
	if err != nil {
		return out, fmt.Errorf("读取配置文件失败: %w", err)
	}

	if sec, err := cfg.GetSection("server"); err == nil {
		if k := sec.Key("HTTP_PORT"); k.String() != "" {
			p, err := k.Int()
			if err != nil {
				return out, fmt.Errorf("server.HTTP_PORT 无效: %w", err)
			}
			if p <= 0 || p > 65535 {
				return out, fmt.Errorf("server.HTTP_PORT 超出范围: %d", p)
			}
			out.Port = p
		}
	}

	if sec, err := cfg.GetSection("paths"); err == nil {
		if v := strings.TrimSpace(sec.Key("DATA").String()); v != "" {
			out.DataRel = v
		}
	}

	if sec, err := cfg.GetSection("security"); err == nil {
		out.JWTSecret = strings.TrimSpace(sec.Key("JWT_SECRET").String())
	}

	if sec, err := cfg.GetSection("community"); err == nil {
		if k := sec.Key("HUB"); k.String() != "" {
			out.CommunityHub = k.MustBool(false)
		}
	}

	return out, nil
}

// writeAppINI 写入/覆盖 app.ini（安装服务或首次生成时使用）
func writeAppINI(path string, s fileSettings) error {
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return err
	}

	var b strings.Builder
	b.WriteString("; 姜十三论坛 Jiang13 Forum — 配置文件（风格类似 Gitea app.ini）\n")
	b.WriteString("; 修改后重启进程/服务生效。命令行参数优先级高于本文件。\n")
	b.WriteString("; OIDC / 邮件 / Gitea 同步 / 对象存储等请在管理后台「系统设置」配置。\n")
	b.WriteString(";\n")
	b.WriteString("; 默认位置：程序工作目录下的 app.ini\n")
	b.WriteString("; 可用 --config / --work-path 覆盖。\n")
	b.WriteString("\n")
	b.WriteString("[server]\n")
	b.WriteString("HTTP_PORT = ")
	b.WriteString(strconv.Itoa(s.Port))
	b.WriteString("\n\n")
	b.WriteString("[paths]\n")
	b.WriteString("; 相对路径相对于工作目录（默认可执行文件所在目录）\n")
	b.WriteString("DATA = ")
	b.WriteString(s.DataRel)
	b.WriteString("\n\n")
	b.WriteString("[security]\n")
	b.WriteString("; 留空则自动生成并持久化到 data/.jwt_secret（勿把生产密钥提交到仓库）\n")
	b.WriteString("JWT_SECRET = ")
	b.WriteString(s.JWTSecret)
	b.WriteString("\n")

	return os.WriteFile(path, []byte(b.String()), 0644)
}

// resolveDataRelForINI 把绝对数据目录尽量写成相对工作目录的路径，便于 app.ini 可读
func resolveDataRelForINI(workPath, absData string) string {
	rel, err := filepath.Rel(workPath, absData)
	if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
		return absData
	}
	return filepath.ToSlash(rel)
}
