package automation

import (
	"context"
	"fmt"
	"strings"
	"time"
)

type AutomationRunBlobSummary struct {
	JobRunID         string
	LogChunks        int64
	LogBytes         int64
	ArtifactCount    int64
	ArtifactBytes    int64
	LatestLogAt      *time.Time
	LatestArtifactAt *time.Time
}

func (s *Store) ListJobsForRun(ctx context.Context, workspaceID string, runID string) ([]AutomationJob, error) {
	if err := s.ensureDB(); err != nil {
		return nil, err
	}
	var jobs []AutomationJob
	err := s.db.WithContext(ctx).
		Where("workspace_id = ? AND run_id = ?", strings.TrimSpace(workspaceID), strings.TrimSpace(runID)).
		Order("scheduled_at ASC").
		Order("id ASC").
		Find(&jobs).Error
	if err != nil {
		return nil, fmt.Errorf("list automation queue jobs for run: %w", err)
	}
	return jobs, nil
}

func (s *Store) ListRunnerSessionsByLeaseOwners(ctx context.Context, workspaceID string, leaseOwners []string) ([]AutomationRunnerSession, error) {
	if err := s.ensureDB(); err != nil {
		return nil, err
	}
	owners := make([]string, 0, len(leaseOwners))
	seen := make(map[string]struct{}, len(leaseOwners))
	for _, owner := range leaseOwners {
		owner = strings.TrimSpace(owner)
		if owner == "" {
			continue
		}
		if _, ok := seen[owner]; ok {
			continue
		}
		seen[owner] = struct{}{}
		owners = append(owners, owner)
	}
	if len(owners) == 0 {
		return nil, nil
	}
	var sessions []AutomationRunnerSession
	err := s.db.WithContext(ctx).
		Where("workspace_id = ? AND lease_owner IN ?", strings.TrimSpace(workspaceID), owners).
		Order("updated_at DESC").
		Find(&sessions).Error
	if err != nil {
		return nil, fmt.Errorf("list automation runner sessions by lease owners: %w", err)
	}
	return sessions, nil
}

func (s *Store) RunBlobSummaries(ctx context.Context, workspaceID string, runID string) ([]AutomationRunBlobSummary, error) {
	if err := s.ensureDB(); err != nil {
		return nil, err
	}
	workspaceID = strings.TrimSpace(workspaceID)
	runID = strings.TrimSpace(runID)
	summaries := make(map[string]*AutomationRunBlobSummary)
	if err := s.addRunLogSummaries(ctx, workspaceID, runID, summaries); err != nil {
		return nil, err
	}
	if err := s.addRunArtifactSummaries(ctx, workspaceID, runID, summaries); err != nil {
		return nil, err
	}
	out := make([]AutomationRunBlobSummary, 0, len(summaries))
	for _, summary := range summaries {
		out = append(out, *summary)
	}
	return out, nil
}

func (s *Store) addRunLogSummaries(ctx context.Context, workspaceID string, runID string, summaries map[string]*AutomationRunBlobSummary) error {
	type logRow struct {
		JobRunID  string
		LogChunks int64
		LogBytes  int64
	}
	var logs []logRow
	err := s.db.WithContext(ctx).
		Model(&AutomationLogChunk{}).
		Select("job_run_id, COUNT(*) AS log_chunks, COALESCE(SUM(size_bytes), 0) AS log_bytes").
		Where("workspace_id = ? AND run_id = ?", workspaceID, runID).
		Group("job_run_id").
		Scan(&logs).Error
	if err != nil {
		return fmt.Errorf("summarize automation log chunks: %w", err)
	}
	for _, row := range logs {
		summary := automationRunBlobSummaryForJob(summaries, row.JobRunID)
		summary.LogChunks = row.LogChunks
		summary.LogBytes = row.LogBytes
	}
	return nil
}

func (s *Store) addRunArtifactSummaries(ctx context.Context, workspaceID string, runID string, summaries map[string]*AutomationRunBlobSummary) error {
	type artifactRow struct {
		JobRunID      string
		ArtifactCount int64
		ArtifactBytes int64
	}
	var artifacts []artifactRow
	err := s.db.WithContext(ctx).
		Model(&AutomationArtifact{}).
		Select("job_run_id, COUNT(*) AS artifact_count, COALESCE(SUM(size_bytes), 0) AS artifact_bytes").
		Where("workspace_id = ? AND run_id = ?", workspaceID, runID).
		Group("job_run_id").
		Scan(&artifacts).Error
	if err != nil {
		return fmt.Errorf("summarize automation artifacts: %w", err)
	}
	for _, row := range artifacts {
		summary := automationRunBlobSummaryForJob(summaries, row.JobRunID)
		summary.ArtifactCount = row.ArtifactCount
		summary.ArtifactBytes = row.ArtifactBytes
	}
	return nil
}

func automationRunBlobSummaryForJob(summaries map[string]*AutomationRunBlobSummary, jobRunID string) *AutomationRunBlobSummary {
	summary := summaries[jobRunID]
	if summary == nil {
		summary = &AutomationRunBlobSummary{JobRunID: jobRunID}
		summaries[jobRunID] = summary
	}
	return summary
}
