package worker

import (
	"context"
	"fmt"
	"time"

	claudeboxclient "github.com/orchard9/rdev/internal/adapter/claudebox"
	"github.com/orchard9/rdev/internal/domain"
	"github.com/orchard9/rdev/internal/logging"
)

// HTTPSDLCTaskExecutor handles WorkTaskTypeSDLC tasks using HTTP calls to the
// local claudebox sidecar instead of kubectl exec.
type HTTPSDLCTaskExecutor struct {
	client  *claudeboxclient.Client
	workDir string
}

// HTTPSDLCTaskExecutorConfig holds configuration for the HTTP SDLC executor.
type HTTPSDLCTaskExecutorConfig struct {
	// ClaudeboxClient is the HTTP client for the claudebox sidecar.
	ClaudeboxClient *claudeboxclient.Client

	// WorkDir is the default working directory in the container.
	WorkDir string
}

// NewHTTPSDLCTaskExecutor creates a new HTTP-based SDLC executor.
func NewHTTPSDLCTaskExecutor(cfg HTTPSDLCTaskExecutorConfig) *HTTPSDLCTaskExecutor {
	if cfg.WorkDir == "" {
		cfg.WorkDir = "/workspace"
	}
	return &HTTPSDLCTaskExecutor{
		client:  cfg.ClaudeboxClient,
		workDir: cfg.WorkDir,
	}
}

// Execute runs an SDLC task using the claudebox sidecar HTTP API.
func (e *HTTPSDLCTaskExecutor) Execute(ctx context.Context, task *domain.WorkTask) *domain.BuildResult {
	start := time.Now()
	log := logging.FromContext(ctx).WithWorker("http-sdlc-executor")

	// Parse SDLC spec
	spec, err := e.parseSpec(task.Spec)
	if err != nil {
		return &domain.BuildResult{
			Success:    false,
			Error:      fmt.Sprintf("invalid SDLC spec: %v", err),
			DurationMs: time.Since(start).Milliseconds(),
		}
	}

	log.Info("executing SDLC task via HTTP",
		"task_id", task.ID,
		logging.FieldProjectID, task.ProjectID,
		"command", spec.Command,
	)

	// Clone repo to workspace
	cloneResp, err := e.client.GitClone(ctx, spec.GitCloneURL, e.workDir)
	if err != nil {
		return &domain.BuildResult{
			Success:    false,
			Error:      fmt.Sprintf("git clone failed: %v", err),
			DurationMs: time.Since(start).Milliseconds(),
		}
	}
	if !cloneResp.Success {
		return &domain.BuildResult{
			Success:    false,
			Error:      fmt.Sprintf("git clone failed: %s", cloneResp.Error),
			DurationMs: time.Since(start).Milliseconds(),
		}
	}

	// Run SDLC command
	sdlcResp, err := e.client.RunSDLC(ctx, spec.Command, spec.Args, e.workDir)
	if err != nil {
		return &domain.BuildResult{
			Success:    false,
			Error:      fmt.Sprintf("sdlc command failed: %v", err),
			DurationMs: time.Since(start).Milliseconds(),
		}
	}
	if !sdlcResp.Success {
		return &domain.BuildResult{
			Success:    false,
			Error:      fmt.Sprintf("sdlc command failed: %s", sdlcResp.Error),
			Output:     sdlcResp.Output,
			DurationMs: time.Since(start).Milliseconds(),
		}
	}

	result := &domain.BuildResult{
		Success:    true,
		Output:     sdlcResp.Output,
		DurationMs: time.Since(start).Milliseconds(),
	}

	// Commit and push if enabled
	if spec.AutoCommit {
		commitMsg := fmt.Sprintf("sdlc: %s", spec.Command)
		gitResp, err := e.client.GitCommitAndPush(ctx, commitMsg, spec.AutoPush, e.workDir)

		if err != nil {
			result.Success = false
			result.Error = fmt.Sprintf("git operations failed: %v", err)
			return result
		}
		if !gitResp.Success {
			result.Success = false
			result.Error = fmt.Sprintf("git operations failed: %s", gitResp.Error)
			return result
		}
		if gitResp.HasChanges {
			result.CommitSHA = gitResp.CommitSHA
			result.FilesChanged = gitResp.FilesChanged
			log.Info("SDLC changes committed",
				"task_id", task.ID,
				"commit", gitResp.CommitSHA,
				"files", len(gitResp.FilesChanged),
				"pushed", gitResp.Pushed,
			)
		}
	}

	log.Info("SDLC task completed",
		"task_id", task.ID,
		"command", spec.Command,
		logging.FieldDuration, result.DurationMs,
	)

	return result
}

// httpSDLCSpec holds typed fields extracted from the task spec map.
type httpSDLCSpec struct {
	Command     string
	Args        []string
	GitCloneURL string
	AutoCommit  bool
	AutoPush    bool
}

// parseSpec extracts typed SDLCTaskSpec fields from the generic map.
func (e *HTTPSDLCTaskExecutor) parseSpec(spec map[string]any) (*httpSDLCSpec, error) {
	command, _ := spec["command"].(string)
	if command == "" {
		return nil, fmt.Errorf("command is required")
	}

	gitCloneURL, _ := spec["git_clone_url"].(string)
	if gitCloneURL == "" {
		return nil, fmt.Errorf("git_clone_url is required")
	}

	autoCommit, _ := spec["auto_commit"].(bool)
	autoPush, _ := spec["auto_push"].(bool)

	// Parse args (can be []string or []any from JSON)
	var args []string
	if argsRaw, ok := spec["args"]; ok {
		switch v := argsRaw.(type) {
		case []string:
			args = v
		case []any:
			for _, a := range v {
				if s, ok := a.(string); ok {
					args = append(args, s)
				}
			}
		}
	}

	return &httpSDLCSpec{
		Command:     command,
		Args:        args,
		GitCloneURL: gitCloneURL,
		AutoCommit:  autoCommit,
		AutoPush:    autoPush,
	}, nil
}
