package store

import (
	"sync"
	"time"

	"bit.admedia.com/scm/ad/adpilot-indexing-commit-intel.com/internal/contracts/metadata"
)

const (
	JobStatusPending   = "pending"
	JobStatusRunning   = "running"
	JobStatusCompleted = "completed"
	JobStatusFailed    = "failed"
)

// AnalysisJob tracks in-memory commit analysis workflow state.
type AnalysisJob struct {
	JobID         string    `json:"job_id"`
	EventID       string    `json:"event_id"`
	RepoID        string    `json:"repo_id"`
	BaseCommitSHA string    `json:"base_commit_sha"`
	TargetCommitSHA string  `json:"target_commit_sha"`
	Status        string    `json:"status"`
	Error         string    `json:"error,omitempty"`
	StartedAt     time.Time `json:"started_at"`
	CompletedAt   time.Time `json:"completed_at,omitempty"`
}

// AnalysisResult holds commit intelligence output for a completed job.
type AnalysisResult struct {
	AnalysisID       string   `json:"analysis_id"`
	RepoID           string   `json:"repo_id"`
	SnapshotID       string   `json:"snapshot_id,omitempty"`
	CommitSHA        string   `json:"commit_sha"`
	BaseCommitSHA    string   `json:"base_commit_sha,omitempty"`
	ImpactedSymbols  []string `json:"impacted_symbols,omitempty"`
	ChangedFiles     []string `json:"changed_files,omitempty"`
	Summary          string   `json:"summary,omitempty"`
	RelatedDocChunks []string `json:"related_doc_chunks,omitempty"`
	metadata.GitCommitMetadata
}

// AnalysisStore provides thread-safe in-memory job and result storage.
type AnalysisStore struct {
	mu        sync.RWMutex
	jobs      map[string]AnalysisJob
	results   map[string]AnalysisResult
	byEventID map[string]string
}

// NewAnalysisStore creates an empty analysis store.
func NewAnalysisStore() *AnalysisStore {
	return &AnalysisStore{
		jobs:      make(map[string]AnalysisJob),
		results:   make(map[string]AnalysisResult),
		byEventID: make(map[string]string),
	}
}

// SaveJob inserts or updates a job record.
func (s *AnalysisStore) SaveJob(job AnalysisJob) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.jobs[job.JobID] = job
	if job.EventID != "" {
		s.byEventID[job.EventID] = job.JobID
	}
}

// GetJob returns a job by ID.
func (s *AnalysisStore) GetJob(jobID string) (AnalysisJob, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	job, ok := s.jobs[jobID]
	return job, ok
}

// GetResult returns analysis output by analysis ID.
func (s *AnalysisStore) GetResult(analysisID string) (AnalysisResult, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	result, ok := s.results[analysisID]
	return result, ok
}

// WasProcessed reports whether an event_id already completed successfully.
func (s *AnalysisStore) WasProcessed(eventID string) bool {
	s.mu.RLock()
	defer s.mu.RUnlock()

	jobID, ok := s.byEventID[eventID]
	if !ok {
		return false
	}
	job, ok := s.jobs[jobID]
	return ok && job.Status == JobStatusCompleted
}

// MarkCompleted stores a successful result and updates job status.
func (s *AnalysisStore) MarkCompleted(jobID string, result AnalysisResult) {
	s.mu.Lock()
	defer s.mu.Unlock()

	job, ok := s.jobs[jobID]
	if !ok {
		return
	}
	job.Status = JobStatusCompleted
	job.CompletedAt = time.Now().UTC()
	job.Error = ""
	s.jobs[jobID] = job
	s.results[result.AnalysisID] = result
}

// MarkFailed updates job status with an error message.
func (s *AnalysisStore) MarkFailed(jobID, message string) {
	s.mu.Lock()
	defer s.mu.Unlock()

	job, ok := s.jobs[jobID]
	if !ok {
		return
	}
	job.Status = JobStatusFailed
	job.Error = message
	job.CompletedAt = time.Now().UTC()
	s.jobs[jobID] = job
}
