package runtime

import (
	"context"
	"errors"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/automation/dsl"
	"github.com/tidbcloud/AgentTeam/internal/store/automation"
)

// TreePublisher publishes a staged file tree into an AGS repository.
type TreePublisher interface {
	PublishRepositoryTree(ctx context.Context, req TreePublishRequest) (TreePublishResult, error)
}

// TreePublishRequest describes one bounded publish operation from a job workdir.
type TreePublishRequest struct {
	WorkspaceID    string
	RunID          string
	JobRunID       string
	Repository     string
	SourcePath     string
	Message        string
	Description    string
	MaxFiles       int
	DefaultBranch  string
	Visibility     string
	RepositoryKind string
}

// TreePublishResult summarizes a completed tree publish.
type TreePublishResult struct {
	Repository string
	Files      int
	Bytes      int64
	CommitSHA  string
}

func (r *ServerRunner) executePublishTreeStep(ctx context.Context, job automation.AutomationJob, jobRun automation.AutomationJobRun, step dsl.StepSpec, stepIndex int, workDir string) error {
	if r.cfg.TreePublisher == nil {
		return fmt.Errorf("automation tree publisher is not configured")
	}
	options, optionErrs := dsl.ParseAgentTeamPublishTreeOptions(step.With)
	if len(optionErrs) > 0 {
		return optionErrs[0]
	}
	sourcePath, err := serverRunnerCheckoutDestination(workDir, options.SourcePath)
	if err != nil {
		return err
	}
	if err := r.appendCheckoutEvent(ctx, job, jobRun, stepIndex, "tree_publish_started", "Automation tree publish started", treePublishEventMetadata(options.Repository, options.SourcePath, nil)); err != nil {
		return err
	}
	result, err := r.cfg.TreePublisher.PublishRepositoryTree(ctx, TreePublishRequest{
		WorkspaceID:    jobRun.WorkspaceID,
		RunID:          jobRun.RunID,
		JobRunID:       jobRun.ID,
		Repository:     options.Repository,
		SourcePath:     sourcePath,
		Message:        options.Message,
		Description:    options.Description,
		MaxFiles:       options.MaxFiles,
		DefaultBranch:  "main",
		Visibility:     "private",
		RepositoryKind: "automation_preset_tree",
	})
	if err != nil {
		failedMetadata := treePublishEventMetadata(options.Repository, options.SourcePath, nil)
		failedMetadata["error"] = err.Error()
		eventErr := r.appendCheckoutEvent(ctx, job, jobRun, stepIndex, "tree_publish_failed", "Automation tree publish failed", failedMetadata)
		if eventErr != nil {
			return errors.Join(fmt.Errorf("automation tree publish failed: %w", err), eventErr)
		}
		return fmt.Errorf("automation tree publish failed: %w", err)
	}
	if err := r.appendCheckoutEvent(ctx, job, jobRun, stepIndex, "tree_publish_succeeded", "Automation tree publish succeeded", treePublishEventMetadata(options.Repository, options.SourcePath, &result)); err != nil {
		return err
	}
	return nil
}

func treePublishEventMetadata(repository string, sourcePath string, result *TreePublishResult) map[string]any {
	sourcePath = strings.TrimSpace(sourcePath)
	if sourcePath == "" {
		sourcePath = "."
	}
	metadata := map[string]any{
		"repository":  strings.TrimSpace(repository),
		"source_path": sourcePath,
	}
	if result == nil {
		return metadata
	}
	metadata["files"] = result.Files
	metadata["bytes"] = result.Bytes
	metadata["commit_sha"] = strings.TrimSpace(result.CommitSHA)
	return metadata
}
