package config

import (
	"encoding/json"
	"fmt"
	"os"
	"sync"
)

// ScheduleRule defines a time-based interval rule.
type ScheduleRule struct {
	Name            string   `json:"name"`
	Days            []string `json:"days"`           // monday, tuesday, wednesday, thursday, friday, saturday, sunday
	TimeRange       string   `json:"time_range"`     // "HH:MM-HH:MM"
	Except          []string `json:"except"`         // ["HH:MM-HH:MM", ...]
	IntervalMinutes int      `json:"interval_minutes"`
}

// ThinkingScheduleConfig is the full schedule configuration.
type ThinkingScheduleConfig struct {
	Version               string         `json:"version"`
	DefaultIntervalMinutes int            `json:"default_interval_minutes"`
	Rules                 []ScheduleRule `json:"rules"`
}

// DefaultThinkingScheduleConfig returns the default schedule with two rules.
func DefaultThinkingScheduleConfig() *ThinkingScheduleConfig {
	return &ThinkingScheduleConfig{
		Version:               "1.0",
		DefaultIntervalMinutes: 5,
		Rules: []ScheduleRule{
			{
				Name:            "night",
				Days:            []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"},
				TimeRange:       "23:00-07:00",
				IntervalMinutes: 30,
			},
			{
				Name:            "weekday_work",
				Days:            []string{"monday", "tuesday", "wednesday", "thursday", "friday"},
				TimeRange:       "09:00-17:00",
				Except:          []string{"12:00-14:00", "15:00-15:30"},
				IntervalMinutes: 30,
			},
		},
	}
}

// ThinkingScheduleStore persists the schedule config to a JSON file.
type ThinkingScheduleStore struct {
	mu     sync.RWMutex
	path   string
	config *ThinkingScheduleConfig
}

// NewThinkingScheduleStore creates a store, creating the file with defaults if it does not exist.
func NewThinkingScheduleStore(path string) (*ThinkingScheduleStore, error) {
	s := &ThinkingScheduleStore{
		path:   path,
		config: nil,
	}
	if err := s.load(); err != nil {
		return nil, err
	}
	return s, nil
}

func (s *ThinkingScheduleStore) load() error {
	data, err := os.ReadFile(s.path)
	if err != nil {
		if os.IsNotExist(err) {
			s.config = DefaultThinkingScheduleConfig()
			return s.save()
		}
		return fmt.Errorf("read thinking schedule file: %w", err)
	}
	if len(data) == 0 {
		s.config = DefaultThinkingScheduleConfig()
		return s.save()
	}
	var cfg ThinkingScheduleConfig
	if err := json.Unmarshal(data, &cfg); err != nil {
		return fmt.Errorf("parse thinking schedule: %w", err)
	}
	if cfg.Version == "" {
		cfg.Version = "1.0"
	}
	if cfg.DefaultIntervalMinutes <= 0 {
		cfg.DefaultIntervalMinutes = 5
	}
	if cfg.Rules == nil {
		cfg.Rules = []ScheduleRule{}
	}
	s.config = &cfg
	return nil
}

func (s *ThinkingScheduleStore) save() error {
	data, err := json.MarshalIndent(s.config, "", "  ")
	if err != nil {
		return fmt.Errorf("marshal thinking schedule: %w", err)
	}
	tmpPath := s.path + ".tmp"
	if err := os.WriteFile(tmpPath, data, 0640); err != nil {
		return fmt.Errorf("write thinking schedule: %w", err)
	}
	return os.Rename(tmpPath, s.path)
}

// GetConfig returns the current config (read-only).
func (s *ThinkingScheduleStore) GetConfig() *ThinkingScheduleConfig {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.config
}

// SetConfig validates and persists a new config.
func (s *ThinkingScheduleStore) SetConfig(cfg *ThinkingScheduleConfig) error {
	if cfg == nil {
		return fmt.Errorf("配置不能为空")
	}
	if cfg.DefaultIntervalMinutes <= 0 {
		cfg.DefaultIntervalMinutes = 5
	}
	if cfg.Version == "" {
		cfg.Version = "1.0"
	}
	if cfg.Rules == nil {
		cfg.Rules = []ScheduleRule{}
	}
	for _, r := range cfg.Rules {
		if r.IntervalMinutes <= 0 {
			return fmt.Errorf("规则 %q 间隔分钟必须大于 0", r.Name)
		}
		if r.TimeRange == "" {
			return fmt.Errorf("规则 %q 缺少 time_range", r.Name)
		}
	}

	s.mu.Lock()
	defer s.mu.Unlock()
	s.config = cfg
	return s.save()
}

// HasConfig returns true if a config is loaded.
func (s *ThinkingScheduleStore) HasConfig() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.config != nil
}
