package tuning

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

// TimeoutLesson represents a learned timeout recommendation
type TimeoutLesson struct {
	ActivityType       string        `json:"activity_type"`
	OldTimeout         time.Duration `json:"old_timeout"`
	NewTimeout         time.Duration `json:"new_timeout"`
	Reason             string        `json:"reason"`
	FailureRate        float64       `json:"failure_rate"`
	SampleSize         int           `json:"sample_size"`
	ConfidenceScore    float64       `json:"confidence_score"`
	AppliedAt          time.Time     `json:"applied_at"`
	Effective          bool          `json:"effective"` // Whether recommendation helped
}

// TimeoutLessonsStore manages timeout lessons for task-specific tuning
type TimeoutLessonsStore struct {
	basePath string
}

// NewTimeoutLessonsStore creates a new timeout lessons store
func NewTimeoutLessonsStore(basePath string) *TimeoutLessonsStore {
	return &TimeoutLessonsStore{
		basePath: basePath,
	}
}

// AppendLesson appends a timeout lesson to the lessons file
func (tls *TimeoutLessonsStore) AppendLesson(taskID string, lesson *TimeoutLesson) error {
	lessonsDir := filepath.Join(tls.basePath, "tuning", "lessons")

	// Create directory if it doesn't exist
	if err := os.MkdirAll(lessonsDir, 0755); err != nil {
		return fmt.Errorf("failed to create lessons directory: %w", err)
	}

	lessonsFile := filepath.Join(lessonsDir, fmt.Sprintf("%s_timeout_lessons.jsonl", taskID))

	// Marshal lesson to JSON
	data, err := json.Marshal(lesson)
	if err != nil {
		return fmt.Errorf("failed to marshal lesson: %w", err)
	}

	// Append to file
	f, err := os.OpenFile(lessonsFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return fmt.Errorf("failed to open lessons file: %w", err)
	}
	defer f.Close()

	_, err = f.Write(append(data, '\n'))
	if err != nil {
		return fmt.Errorf("failed to write lesson: %w", err)
	}

	return nil
}

// ReadLessons reads all timeout lessons for a task
func (tls *TimeoutLessonsStore) ReadLessons(taskID string) ([]*TimeoutLesson, error) {
	lessonsFile := filepath.Join(tls.basePath, "tuning", "lessons", fmt.Sprintf("%s_timeout_lessons.jsonl", taskID))

	// If file doesn't exist, return empty list
	if _, err := os.Stat(lessonsFile); os.IsNotExist(err) {
		return nil, nil
	}

	data, err := os.ReadFile(lessonsFile)
	if err != nil {
		return nil, fmt.Errorf("failed to read lessons file: %w", err)
	}

	var lessons []*TimeoutLesson
	content := string(data)

	// Parse JSONL line by line
	var inLine []byte
	for _, ch := range []byte(content) {
		if ch == '\n' {
			if len(inLine) > 0 {
				var lesson TimeoutLesson
				if err := json.Unmarshal(inLine, &lesson); err == nil {
					lessons = append(lessons, &lesson)
				}
			}
			inLine = nil
		} else {
			inLine = append(inLine, ch)
		}
	}

	return lessons, nil
}

// GetLatestLesson returns the most recent timeout lesson for a task
func (tls *TimeoutLessonsStore) GetLatestLesson(taskID string) (*TimeoutLesson, error) {
	lessons, err := tls.ReadLessons(taskID)
	if err != nil {
		return nil, err
	}

	if len(lessons) == 0 {
		return nil, nil
	}

	return lessons[len(lessons)-1], nil
}

// GenerateLessonFromRecommendation creates a lesson from a timeout recommendation
func GenerateLessonFromRecommendation(rec *TimeoutRecommendation) *TimeoutLesson {
	if rec == nil {
		return nil
	}

	failureRate := 0.0
	if rec.SuccessCount+rec.FailureCount > 0 {
		failureRate = float64(rec.FailureCount) / float64(rec.SuccessCount+rec.FailureCount)
	}

	return &TimeoutLesson{
		ActivityType:    rec.ActivityType,
		OldTimeout:      rec.CurrentTimeout,
		NewTimeout:      rec.RecommendedTimeout,
		Reason:          rec.Reason,
		FailureRate:     failureRate,
		SampleSize:      rec.SuccessCount + rec.FailureCount,
		ConfidenceScore: rec.Confidence,
		AppliedAt:       time.Now(),
		Effective:       false, // To be determined after next run
	}
}

// FormatLessonsForPlanner formats timeout lessons for planner input
func FormatLessonsForPlanner(lessons []*TimeoutLesson) string {
	if len(lessons) == 0 {
		return "No timeout lessons available."
	}

	output := "Recent timeout lessons learned:\n"
	for i, lesson := range lessons {
		output += fmt.Sprintf(
			"\n[Lesson %d] %s:\n  Old Timeout: %v → New Timeout: %v\n  Reason: %s\n  Confidence: %.1f%%\n",
			i+1,
			lesson.ActivityType,
			lesson.OldTimeout,
			lesson.NewTimeout,
			lesson.Reason,
			lesson.ConfidenceScore*100,
		)
	}

	return output
}

// TimeoutTuningSignal represents a signal to update timeout tuning
type TimeoutTuningSignal struct {
	ActivityType   string        `json:"activity_type"`
	NewTimeout     time.Duration `json:"new_timeout"`
	Reason         string        `json:"reason"`
	Confidence     float64       `json:"confidence"`
	Priority       string        `json:"priority"` // "low", "medium", "high"
}

// GenerateSignalsFromRecommendations generates tuning signals from recommendations
func GenerateSignalsFromRecommendations(recommendations []TimeoutRecommendation) []TimeoutTuningSignal {
	signals := make([]TimeoutTuningSignal, 0)

	for _, rec := range recommendations {
		priority := "low"
		if rec.Confidence > 0.7 {
			priority = "high"
		} else if rec.Confidence > 0.5 {
			priority = "medium"
		}

		signal := TimeoutTuningSignal{
			ActivityType: rec.ActivityType,
			NewTimeout:   rec.RecommendedTimeout,
			Reason:       rec.Reason,
			Confidence:   rec.Confidence,
			Priority:     priority,
		}

		signals = append(signals, signal)
	}

	return signals
}
