// Package ai provides AI-powered infrastructure monitoring and investigation.
package ai

import (
	"sync"
	"time"

	"github.com/rcourtman/pulse-go-rewrite/internal/config"
	"github.com/rs/zerolog/log"
)

// PatrolHistoryPersistence interface for saving/loading patrol run history
type PatrolHistoryPersistence interface {
	SavePatrolRunHistory(runs []PatrolRunRecord) error
	LoadPatrolRunHistory() ([]PatrolRunRecord, error)
}

// PatrolHistoryPersistenceAdapter bridges ConfigPersistence to PatrolHistoryPersistence interface
type PatrolHistoryPersistenceAdapter struct {
	config *config.ConfigPersistence
}

// NewPatrolHistoryPersistenceAdapter creates a new adapter
func NewPatrolHistoryPersistenceAdapter(cfg *config.ConfigPersistence) *PatrolHistoryPersistenceAdapter {
	return &PatrolHistoryPersistenceAdapter{config: cfg}
}

// SavePatrolRunHistory saves patrol run history to disk via ConfigPersistence
func (a *PatrolHistoryPersistenceAdapter) SavePatrolRunHistory(runs []PatrolRunRecord) error {
	// Convert from ai.PatrolRunRecord to config.PatrolRunRecord
	records := make([]config.PatrolRunRecord, len(runs))
	for i, r := range runs {
		records[i] = config.PatrolRunRecord{
			ID:               r.ID,
			StartedAt:        r.StartedAt,
			CompletedAt:      r.CompletedAt,
			DurationMs:       int64(r.Duration),
			Type:             r.Type,
			ResourcesChecked: r.ResourcesChecked,
			NodesChecked:     r.NodesChecked,
			GuestsChecked:    r.GuestsChecked,
			DockerChecked:    r.DockerChecked,
			StorageChecked:   r.StorageChecked,
			HostsChecked:     r.HostsChecked,
			PBSChecked:       r.PBSChecked,
			NewFindings:      r.NewFindings,
			ExistingFindings: r.ExistingFindings,
			ResolvedFindings: r.ResolvedFindings,
			FindingsSummary:  r.FindingsSummary,
			FindingIDs:       r.FindingIDs,
			ErrorCount:       r.ErrorCount,
			Status:           r.Status,
			AIAnalysis:       r.AIAnalysis,
			InputTokens:      r.InputTokens,
			OutputTokens:     r.OutputTokens,
		}
	}
	return a.config.SavePatrolRunHistory(records)
}

// LoadPatrolRunHistory loads patrol run history from disk via ConfigPersistence
func (a *PatrolHistoryPersistenceAdapter) LoadPatrolRunHistory() ([]PatrolRunRecord, error) {
	data, err := a.config.LoadPatrolRunHistory()
	if err != nil {
		return nil, err
	}

	// Convert from config.PatrolRunRecord to ai.PatrolRunRecord
	runs := make([]PatrolRunRecord, len(data.Runs))
	for i, r := range data.Runs {
		runs[i] = PatrolRunRecord{
			ID:               r.ID,
			StartedAt:        r.StartedAt,
			CompletedAt:      r.CompletedAt,
			Duration:         time.Duration(r.DurationMs),
			Type:             r.Type,
			ResourcesChecked: r.ResourcesChecked,
			NodesChecked:     r.NodesChecked,
			GuestsChecked:    r.GuestsChecked,
			DockerChecked:    r.DockerChecked,
			StorageChecked:   r.StorageChecked,
			HostsChecked:     r.HostsChecked,
			PBSChecked:       r.PBSChecked,
			NewFindings:      r.NewFindings,
			ExistingFindings: r.ExistingFindings,
			ResolvedFindings: r.ResolvedFindings,
			FindingsSummary:  r.FindingsSummary,
			FindingIDs:       r.FindingIDs,
			ErrorCount:       r.ErrorCount,
			Status:           r.Status,
			AIAnalysis:       r.AIAnalysis,
			InputTokens:      r.InputTokens,
			OutputTokens:     r.OutputTokens,
		}
	}
	return runs, nil
}

// PatrolRunHistoryStore provides thread-safe storage for patrol run history with optional persistence
type PatrolRunHistoryStore struct {
	mu          sync.RWMutex
	runs        []PatrolRunRecord
	maxRuns     int
	persistence PatrolHistoryPersistence
	// Debounce save operations
	saveTimer    *time.Timer
	savePending  bool
	saveDebounce time.Duration
}

// NewPatrolRunHistoryStore creates a new patrol run history store
func NewPatrolRunHistoryStore(maxRuns int) *PatrolRunHistoryStore {
	if maxRuns <= 0 {
		maxRuns = MaxPatrolRunHistory
	}
	return &PatrolRunHistoryStore{
		runs:         make([]PatrolRunRecord, 0, maxRuns),
		maxRuns:      maxRuns,
		saveDebounce: 5 * time.Second,
	}
}

// SetPersistence sets the persistence layer and loads existing history
func (s *PatrolRunHistoryStore) SetPersistence(p PatrolHistoryPersistence) error {
	s.mu.Lock()
	s.persistence = p
	s.mu.Unlock()

	// Load existing history from disk
	if p != nil {
		runs, err := p.LoadPatrolRunHistory()
		if err != nil {
			return err
		}
		if len(runs) > 0 {
			s.mu.Lock()
			s.runs = runs
			// Trim to max if loaded more than maxRuns
			if len(s.runs) > s.maxRuns {
				s.runs = s.runs[:s.maxRuns]
			}
			s.mu.Unlock()
			log.Info().Int("count", len(runs)).Msg("Loaded patrol run history from disk")
		}
	}
	return nil
}

// Add adds a new patrol run to the history
func (s *PatrolRunHistoryStore) Add(run PatrolRunRecord) {
	s.mu.Lock()
	defer s.mu.Unlock()

	// Prepend (newest first)
	s.runs = append([]PatrolRunRecord{run}, s.runs...)
	
	// Trim to max
	if len(s.runs) > s.maxRuns {
		s.runs = s.runs[:s.maxRuns]
	}

	// Schedule save
	s.scheduleSave()
}

// GetAll returns all runs (newest first)
func (s *PatrolRunHistoryStore) GetAll() []PatrolRunRecord {
	s.mu.RLock()
	defer s.mu.RUnlock()
	
	result := make([]PatrolRunRecord, len(s.runs))
	copy(result, s.runs)
	return result
}

// GetRecent returns at most n recent runs
func (s *PatrolRunHistoryStore) GetRecent(n int) []PatrolRunRecord {
	s.mu.RLock()
	defer s.mu.RUnlock()
	
	if n <= 0 || n > len(s.runs) {
		n = len(s.runs)
	}
	
	result := make([]PatrolRunRecord, n)
	copy(result, s.runs[:n])
	return result
}

// Count returns the number of runs in history
func (s *PatrolRunHistoryStore) Count() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return len(s.runs)
}

// scheduleSave schedules a debounced save operation
func (s *PatrolRunHistoryStore) scheduleSave() {
	if s.persistence == nil {
		return
	}

	// Cancel existing timer if pending
	if s.saveTimer != nil {
		s.saveTimer.Stop()
	}

	s.savePending = true
	s.saveTimer = time.AfterFunc(s.saveDebounce, func() {
		s.mu.Lock()
		if !s.savePending {
			s.mu.Unlock()
			return
		}
		s.savePending = false
		// Copy runs while locked
		runs := make([]PatrolRunRecord, len(s.runs))
		copy(runs, s.runs)
		persistence := s.persistence
		s.mu.Unlock()

		// Save outside lock
		if persistence != nil {
			if err := persistence.SavePatrolRunHistory(runs); err != nil {
				log.Error().Err(err).Msg("Failed to save patrol run history")
			}
		}
	})
}

// FlushPersistence immediately saves any pending changes
func (s *PatrolRunHistoryStore) FlushPersistence() error {
	s.mu.Lock()
	if s.saveTimer != nil {
		s.saveTimer.Stop()
	}
	s.savePending = false
	runs := make([]PatrolRunRecord, len(s.runs))
	copy(runs, s.runs)
	persistence := s.persistence
	s.mu.Unlock()

	if persistence != nil {
		return persistence.SavePatrolRunHistory(runs)
	}
	return nil
}
