package taskutil

import (
	"context"
	"log"

	"chat-switchboard/models"
	"chat-switchboard/store"
)

// TaskConfig holds the runtime task configuration read from global_settings.
// Keys: tasks.enabled, tasks.allow_personal, tasks.max_concurrent,
//       tasks.default_max_tokens, tasks.default_max_tool_calls,
//       tasks.default_max_wall_clock, tasks.personal_require_byok
type TaskConfig struct {
	Enabled              bool
	AllowPersonal        bool
	PersonalRequireBYOK  bool
	MaxConcurrent        int
	DefaultMaxTokens     int
	DefaultMaxToolCalls  int
	DefaultMaxWallClock  int // seconds
}

// DefaultTaskConfig returns sensible defaults when no global config is set.
func DefaultTaskConfig() TaskConfig {
	return TaskConfig{
		Enabled:              true,
		AllowPersonal:        true,
		PersonalRequireBYOK:  false,
		MaxConcurrent:        5,
		DefaultMaxTokens:     4096,
		DefaultMaxToolCalls:  10,
		DefaultMaxWallClock:  300,
	}
}

// LoadTaskConfig reads task configuration from global_settings.
// Falls back to defaults for missing keys.
func LoadTaskConfig(ctx context.Context, gc store.GlobalConfigStore) TaskConfig {
	cfg := DefaultTaskConfig()
	if gc == nil {
		return cfg
	}

	raw, err := gc.Get(ctx, "tasks")
	if err != nil || raw == nil {
		return cfg
	}

	if v, ok := boolVal(raw, "enabled"); ok {
		cfg.Enabled = v
	}
	if v, ok := boolVal(raw, "allow_personal"); ok {
		cfg.AllowPersonal = v
	}
	if v, ok := boolVal(raw, "personal_require_byok"); ok {
		cfg.PersonalRequireBYOK = v
	}
	if v, ok := intVal(raw, "max_concurrent"); ok && v > 0 {
		cfg.MaxConcurrent = v
	}
	if v, ok := intVal(raw, "default_max_tokens"); ok && v > 0 {
		cfg.DefaultMaxTokens = v
	}
	if v, ok := intVal(raw, "default_max_tool_calls"); ok && v > 0 {
		cfg.DefaultMaxToolCalls = v
	}
	if v, ok := intVal(raw, "default_max_wall_clock"); ok && v > 0 {
		cfg.DefaultMaxWallClock = v
	}

	return cfg
}

// ApplyDefaults fills zero-value budget fields on a task with the global defaults.
func (tc TaskConfig) ApplyDefaults(t *models.Task) {
	if t.MaxTokens == 0 {
		t.MaxTokens = tc.DefaultMaxTokens
	}
	if t.MaxToolCalls == 0 {
		t.MaxToolCalls = tc.DefaultMaxToolCalls
	}
	if t.MaxWallClock == 0 {
		t.MaxWallClock = tc.DefaultMaxWallClock
	}
}

// ── helpers ────────────────────────────────────

func boolVal(m models.JSONMap, key string) (bool, bool) {
	v, ok := m[key]
	if !ok {
		return false, false
	}
	b, ok := v.(bool)
	return b, ok
}

func intVal(m models.JSONMap, key string) (int, bool) {
	v, ok := m[key]
	if !ok {
		return 0, false
	}
	// JSON numbers are float64 after Unmarshal
	switch n := v.(type) {
	case float64:
		return int(n), true
	case int:
		return n, true
	default:
		log.Printf("[task_config] unexpected type for %s: %T", key, v)
		return 0, false
	}
}
