package config

import (
	"encoding/json"
	"os"
	"path/filepath"
)

type ExportSettings struct {
	GenerateSitemap bool `json:"generate_sitemap"`
	GenerateIndex   bool `json:"generate_index"`
	GenerateAbout   bool `json:"generate_about"`
	RelatedCount    int  `json:"related_articles_count"`
}

type MemorySettings struct {
	BatchSize      int  `json:"batch_size"`
	CacheJSON      bool `json:"cache_json"`
	CacheTemplates bool `json:"cache_templates"`
}

type AISettings struct {
	BaseURL        string   `json:"base_url"`
	APIKey         string   `json:"api_key"`
	KeyFile        string   `json:"key_file"`
	Model          string   `json:"model"`
	Concurrency    int      `json:"concurrency"`
	FallbackModels []string `json:"fallback_models"`
	MaxRetries     int      `json:"max_retries"`
	RetryDelay     int      `json:"retry_delay"`
}

type GoSettings struct {
	WarmupRequests     bool    `json:"warmup_requests"`
	WriterBatchSize    int     `json:"writer_batch_size"`
	GlobalRatePerSec   float64 `json:"global_rate_per_sec"`
	ProxyRatePerSec    float64 `json:"proxy_rate_per_sec"`
	AdaptiveRate       bool    `json:"adaptive_rate"`
	AIWriterBatchSize  int     `json:"ai_writer_batch_size"`
	SessionBankSize    int     `json:"session_bank_size"`
	SessionRotateAfter int     `json:"session_rotate_after"`
}

type Config struct {
	SplitSize          int            `json:"split_size"`
	WorkerCount        int            `json:"worker_count"`
	Template           string         `json:"template"`
	ExportFolder       string         `json:"export_folder"`
	DataFolder         string         `json:"data_folder"`
	InjectFolder       string         `json:"inject_folder"`
	Export             ExportSettings `json:"export"`
	Memory             MemorySettings `json:"memory"`
	ImageResult        int            `json:"image_result"`
	MinSnippet         int            `json:"min_snippet"`
	SnippetMaxPageSize int            `json:"snippet_max_page_size"`
	MaxRelatedKw       int            `json:"max_related_kw"`
	SuggestHl          string         `json:"suggest_hl"`
	SuggestGl          string         `json:"suggest_gl"`
	Concurrency        int            `json:"concurrency"`
	MaxRetries         int            `json:"max_retries"`
	RetryDelay         int            `json:"retry_delay"`
	AI                 AISettings     `json:"ai"`
	Go                 GoSettings     `json:"go"`

	Root string `json:"-"`
}

func defaults(c *Config) {
	if c.SplitSize <= 0 {
		c.SplitSize = 5000
	}
	if c.WorkerCount <= 0 {
		c.WorkerCount = 4
	}
	if c.Template == "" {
		c.Template = "modern"
	}
	if c.ExportFolder == "" {
		c.ExportFolder = "export"
	}
	if c.DataFolder == "" {
		c.DataFolder = "database"
	}
	if c.InjectFolder == "" {
		c.InjectFolder = "inject"
	}
	if c.Memory.BatchSize <= 0 {
		c.Memory.BatchSize = 100
	}
	if c.ImageResult <= 0 {
		c.ImageResult = 7
	}
	if c.MinSnippet <= 0 {
		c.MinSnippet = 10
	}
	if c.SnippetMaxPageSize <= 0 {
		c.SnippetMaxPageSize = 50
	}
	if c.MaxRelatedKw <= 0 {
		c.MaxRelatedKw = 10
	}
	if c.SuggestHl == "" {
		c.SuggestHl = "en"
	}
	if c.SuggestGl == "" {
		c.SuggestGl = "US"
	}
	if c.Concurrency <= 0 {
		c.Concurrency = 30
	}
	if c.MaxRetries <= 0 {
		c.MaxRetries = 3
	}
	if c.RetryDelay <= 0 {
		c.RetryDelay = 3
	}
	if c.AI.Model == "" {
		c.AI.Model = "gpt-3.5-turbo"
	}
	if c.AI.BaseURL == "" {
		c.AI.BaseURL = "https://api.openai.com/v1"
	}
	if c.AI.Concurrency <= 0 {
		c.AI.Concurrency = 100
	}
	if c.AI.MaxRetries <= 0 {
		c.AI.MaxRetries = 2
	}
	if c.AI.RetryDelay <= 0 {
		c.AI.RetryDelay = 5
	}
	if c.Go.WriterBatchSize <= 0 {
		c.Go.WriterBatchSize = 100
	}
	if c.Go.AIWriterBatchSize <= 0 {
		c.Go.AIWriterBatchSize = 200
	}
	if c.Go.GlobalRatePerSec <= 0 {
		c.Go.GlobalRatePerSec = 0
	}
	if c.Go.ProxyRatePerSec <= 0 {
		c.Go.ProxyRatePerSec = 0
	}
	if c.Go.SessionBankSize <= 0 {
		c.Go.SessionBankSize = 12
	}
	if c.Go.SessionRotateAfter <= 0 {
		c.Go.SessionRotateAfter = 50
	}
}

// Load reads config.json from root and fills defaults. Root must contain config.json.
func Load(root string) (*Config, error) {
	path := filepath.Join(root, "config.json")
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}
	var c Config
	if err := json.Unmarshal(data, &c); err != nil {
		return nil, err
	}
	c.Root = root
	defaults(&c)
	return &c, nil
}

// FindRoot locates the project root containing config.json, starting from exeDir and cwd.
func FindRoot() string {
	exePath, err := os.Executable()
	if err != nil {
		exePath, _ = os.Getwd()
	}
	exeDir := filepath.Dir(exePath)
	candidates := []string{
		exeDir,
		filepath.Join(exeDir, ".."),
		filepath.Join(exeDir, "..", ".."),
	}
	if cwd, err := os.Getwd(); err == nil {
		candidates = append(candidates, cwd, filepath.Join(cwd, ".."), filepath.Join(cwd, "..", ".."))
	}
	for _, dir := range candidates {
		if _, err := os.Stat(filepath.Join(dir, "config.json")); err == nil {
			abs, err := filepath.Abs(dir)
			if err == nil {
				return abs
			}
			return dir
		}
	}
	cwd, _ := os.Getwd()
	return cwd
}

func (c *Config) Path(parts ...string) string {
	all := append([]string{c.Root}, parts...)
	return filepath.Join(all...)
}
