// Package service provides business logic services.
package service

import (
	"context"
	"fmt"
	"time"

	"github.com/orchard9/rdev/internal/domain"
	"github.com/orchard9/rdev/internal/logging"
	"github.com/orchard9/rdev/internal/port"
)

// BuildService orchestrates build task submission and tracking.
// It coordinates between the work queue (execution) and build audit (history).
type BuildService struct {
	queue port.WorkQueue
	audit port.BuildAudit
}

// NewBuildService creates a new build service.
func NewBuildService(
	queue port.WorkQueue,
	audit port.BuildAudit,
) *BuildService {
	return &BuildService{
		queue: queue,
		audit: audit,
	}
}

// StartBuild enqueues a build task and creates an audit entry.
// Returns the task ID for status tracking.
func (s *BuildService) StartBuild(ctx context.Context, projectID string, spec domain.BuildSpec) (string, error) {
	if err := spec.Validate(); err != nil {
		return "", err
	}

	if projectID == "" {
		return "", fmt.Errorf("project_id is required")
	}

	// Build work task spec from build spec
	taskSpec := map[string]any{
		"prompt":      spec.Prompt,
		"auto_commit": spec.AutoCommit,
		"auto_push":   spec.AutoPush,
	}
	if spec.Template != "" {
		taskSpec["template"] = spec.Template
	}
	if len(spec.Variables) > 0 {
		taskSpec["variables"] = spec.Variables
	}
	if spec.GitCloneURL != "" {
		taskSpec["git_clone_url"] = spec.GitCloneURL
	}

	// Create work task
	task := &domain.WorkTask{
		ProjectID:   projectID,
		Type:        domain.WorkTaskTypeBuild,
		Spec:        taskSpec,
		CallbackURL: spec.CallbackURL,
		MaxRetries:  3,
	}

	// Enqueue to work queue
	taskID, err := s.queue.Enqueue(ctx, task)
	if err != nil {
		return "", fmt.Errorf("enqueue build task: %w", err)
	}

	// Create audit entry (non-critical - don't fail the build if audit fails)
	auditEntry := &domain.BuildAuditEntry{
		TaskID:    taskID,
		ProjectID: projectID,
		Spec:      spec,
		Status:    domain.BuildStatusPending,
		StartedAt: time.Now(),
	}
	log := logging.FromContext(ctx).WithService("build")
	if err := s.audit.Record(ctx, auditEntry); err != nil {
		log.Warn("failed to record audit entry",
			"task_id", taskID,
			logging.FieldError, err.Error(),
		)
	}

	log.Info("build enqueued",
		"task_id", taskID,
		logging.FieldProjectID, projectID,
		"template", spec.Template,
		"auto_push", spec.AutoPush,
	)

	return taskID, nil
}

// GetBuildStatus returns the current status of a build.
func (s *BuildService) GetBuildStatus(ctx context.Context, taskID string) (*domain.BuildAuditEntry, error) {
	return s.audit.Get(ctx, taskID)
}

// ListBuilds returns build history for a project.
func (s *BuildService) ListBuilds(ctx context.Context, projectID string, limit int) ([]*domain.BuildAuditEntry, error) {
	if limit <= 0 {
		limit = 50
	}
	return s.audit.List(ctx, port.BuildAuditFilter{
		ProjectID: projectID,
		Limit:     limit,
	})
}

// CompleteBuild updates the audit entry when a build finishes.
// Called by the work queue processor on task completion.
func (s *BuildService) CompleteBuild(ctx context.Context, taskID string, result *domain.BuildResult) error {
	if err := s.audit.Update(ctx, taskID, result); err != nil {
		return fmt.Errorf("update audit: %w", err)
	}

	log := logging.FromContext(ctx).WithService("build")
	log.Info("build completed",
		"task_id", taskID,
		"success", result.Success,
		logging.FieldDuration, result.DurationMs,
	)

	return nil
}

// StartBuildWithSDLCContext enqueues a build task with SDLC context for callback routing.
// The SDLC context is included in the task spec and will be passed through to the callback.
func (s *BuildService) StartBuildWithSDLCContext(ctx context.Context, projectID string, spec domain.BuildSpec, sdlcCtx map[string]any) (string, error) {
	if err := spec.Validate(); err != nil {
		return "", err
	}

	if projectID == "" {
		return "", fmt.Errorf("project_id is required")
	}

	// Build work task spec from build spec
	taskSpec := map[string]any{
		"prompt":      spec.Prompt,
		"auto_commit": spec.AutoCommit,
		"auto_push":   spec.AutoPush,
	}
	if spec.Template != "" {
		taskSpec["template"] = spec.Template
	}
	if len(spec.Variables) > 0 {
		taskSpec["variables"] = spec.Variables
	}
	if spec.GitCloneURL != "" {
		taskSpec["git_clone_url"] = spec.GitCloneURL
	}
	// Add SDLC context for callback routing
	if sdlcCtx != nil {
		taskSpec["sdlc_context"] = sdlcCtx
	}

	// Create work task
	task := &domain.WorkTask{
		ProjectID:   projectID,
		Type:        domain.WorkTaskTypeBuild,
		Spec:        taskSpec,
		CallbackURL: spec.CallbackURL,
		MaxRetries:  3,
	}

	// Enqueue to work queue
	taskID, err := s.queue.Enqueue(ctx, task)
	if err != nil {
		return "", fmt.Errorf("enqueue build task: %w", err)
	}

	// Create audit entry (non-critical - don't fail the build if audit fails)
	auditEntry := &domain.BuildAuditEntry{
		TaskID:    taskID,
		ProjectID: projectID,
		Spec:      spec,
		Status:    domain.BuildStatusPending,
		StartedAt: time.Now(),
	}
	log := logging.FromContext(ctx).WithService("build")
	if err := s.audit.Record(ctx, auditEntry); err != nil {
		log.Warn("failed to record audit entry",
			"task_id", taskID,
			logging.FieldError, err.Error(),
		)
	}

	log.Info("build enqueued with SDLC context",
		"task_id", taskID,
		logging.FieldProjectID, projectID,
		"sdlc_context", sdlcCtx,
	)

	return taskID, nil
}
