package automation

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/contentpayload"
	"github.com/tidbcloud/AgentTeam/internal/service/automation/runtime"
	"github.com/tidbcloud/AgentTeam/internal/service/content"
)

type AutomationContentTreeReader interface {
	GetVersion(context.Context, string, string, string) (content.Version, error)
	MaterializeTree(context.Context, string, string, string, string, contentpayload.MaterializeLimits) error
}

// ContentStoreAutomationCheckoutMaterializer restores one exact immutable
// ContentVersion into a server-runner workspace without repository or Git refs.
type ContentStoreAutomationCheckoutMaterializer struct {
	Content      AutomationContentTreeReader
	MaxFileBytes int64
}

func (materializer ContentStoreAutomationCheckoutMaterializer) Materialize(ctx context.Context, request runtime.CheckoutRequest) (runtime.CheckoutResult, error) {
	if ctx == nil {
		ctx = context.Background()
	}
	if materializer.Content == nil {
		return runtime.CheckoutResult{}, fmt.Errorf("automation content checkout is not configured")
	}
	workspaceID := strings.TrimSpace(request.WorkspaceID)
	contentID := strings.TrimSpace(request.ContentID)
	versionID := strings.TrimSpace(request.ContentVersionID)
	if workspaceID == "" || contentID == "" || versionID == "" {
		return runtime.CheckoutResult{}, fmt.Errorf("automation content checkout requires workspace, content, and version")
	}
	ctx = WithAutomationContentAccess(ctx, workspaceID, "", contentID, 0, request.PrincipalID,
		content.AccessReadMetadata, content.AccessReadPayload)
	maxFileBytes := materializer.MaxFileBytes
	if maxFileBytes <= 0 || maxFileBytes > contentpayload.DefaultLimits.MaxFileBytes {
		maxFileBytes = contentpayload.DefaultLimits.MaxFileBytes
	}
	limits := contentpayload.MaterializeLimits{MaxFiles: request.MaxFiles, MaxFileBytes: maxFileBytes, MaxTotalBytes: request.MaxBytes}
	version, err := materializer.Content.GetVersion(ctx, workspaceID, contentID, versionID)
	if err != nil {
		return runtime.CheckoutResult{}, fmt.Errorf("load automation content version: %w", err)
	}
	if version.FileCount > limits.MaxFiles || version.SizeBytes > limits.MaxTotalBytes {
		return runtime.CheckoutResult{}, fmt.Errorf("automation content version exceeds checkout bounds")
	}
	destination, err := prepareAutomationContentCheckoutDestination(request.Destination, request.Clean)
	if err != nil {
		return runtime.CheckoutResult{}, err
	}
	started := time.Now()
	if err := materializer.Content.MaterializeTree(ctx, workspaceID, contentID, versionID, destination, limits); err != nil {
		return runtime.CheckoutResult{}, fmt.Errorf("materialize automation content version: %w", err)
	}
	return runtime.CheckoutResult{Strategy: "content_version", Files: version.FileCount, Bytes: version.SizeBytes, Duration: time.Since(started)}, nil
}

func prepareAutomationContentCheckoutDestination(destination string, clean bool) (string, error) {
	if strings.TrimSpace(destination) == "" {
		return "", fmt.Errorf("automation checkout destination is required")
	}
	abs, err := filepath.Abs(destination)
	if err != nil {
		return "", fmt.Errorf("resolve automation checkout destination: %w", err)
	}
	if err := rejectAutomationCheckoutSymlinkAncestors(abs); err != nil {
		return "", err
	}
	if clean {
		if err := os.RemoveAll(abs); err != nil {
			return "", fmt.Errorf("clean automation checkout destination: %w", err)
		}
	} else if _, err := os.Lstat(abs); err == nil {
		return "", fmt.Errorf("automation checkout destination already exists")
	} else if !os.IsNotExist(err) {
		return "", fmt.Errorf("inspect automation checkout destination: %w", err)
	}
	if err := os.MkdirAll(filepath.Dir(abs), 0o755); err != nil {
		return "", fmt.Errorf("create automation checkout destination parent: %w", err)
	}
	if err := rejectAutomationCheckoutSymlinkAncestors(abs); err != nil {
		return "", err
	}
	return abs, nil
}
