package openai

import (
	"encoding/json"
	"fmt"
	"strings"
	"unicode"
)

const hotPathWorkerReviewToolName = "iop_write_worker_review"

type hotPathArtifactPaths struct {
	PlanPath   string
	ReviewPath string
}

type hotPathStageCorrelation struct {
	StageID    string
	ResponseID string
	RunID      string
	ProviderID string
	Terminal   string
}

// hotPathStageInput is the complete cross-stage input boundary. It contains
// only caller-owned immutable task text, issued relative paths, and committed
// provider correlations. Workspace contents, credentials, provider targets,
// and prior control prompts never enter this value.
type hotPathStageInput struct {
	Role           string
	ImmutableTask  string
	Artifacts      hotPathArtifactPaths
	SelectorCommit hotPathStageCorrelation
	LocalCommit    hotPathStageCorrelation
}

func buildLocalStageInput(task string, paths reservedPaths, selector hotPathStageCorrelation) hotPathStageInput {
	return hotPathStageInput{
		Role:          "local",
		ImmutableTask: strings.TrimSpace(task),
		Artifacts: hotPathArtifactPaths{
			PlanPath:   paths.PlanPath,
			ReviewPath: paths.ReviewPath,
		},
		SelectorCommit: selector,
	}
}

func buildReviewStageInput(task string, paths reservedPaths, selector, local hotPathStageCorrelation) hotPathStageInput {
	return hotPathStageInput{
		Role:          "review",
		ImmutableTask: strings.TrimSpace(task),
		Artifacts: hotPathArtifactPaths{
			PlanPath:   paths.PlanPath,
			ReviewPath: paths.ReviewPath,
		},
		SelectorCommit: selector,
		LocalCommit:    local,
	}
}

func (in hotPathStageInput) validate() error {
	if strings.TrimSpace(in.ImmutableTask) == "" {
		return fmt.Errorf("immutable user task is empty")
	}
	if cleanRelativePath(in.Artifacts.PlanPath) == "" || cleanRelativePath(in.Artifacts.ReviewPath) == "" {
		return fmt.Errorf("issued artifact paths are unavailable")
	}
	if err := validateStageCorrelation("selector", in.SelectorCommit); err != nil {
		return err
	}
	if in.Role == "review" {
		if err := validateStageCorrelation("local", in.LocalCommit); err != nil {
			return err
		}
	}
	return nil
}

func validateStageCorrelation(role string, correlation hotPathStageCorrelation) error {
	if !validLogicalRequestID(correlation.StageID) {
		return fmt.Errorf("%s commit correlation StageID %q is invalid", role, correlation.StageID)
	}
	if !validOpaqueStageCorrelation(correlation.ResponseID) {
		return fmt.Errorf("%s commit correlation ResponseID is invalid", role)
	}
	if !validLogicalRequestID(correlation.RunID) {
		return fmt.Errorf("%s commit correlation RunID %q is invalid", role, correlation.RunID)
	}
	if !validOpaqueStageCorrelation(correlation.ProviderID) {
		return fmt.Errorf("%s commit correlation ProviderID is invalid", role)
	}
	if !validOpaqueStageCorrelation(correlation.Terminal) {
		return fmt.Errorf("%s commit correlation Terminal is invalid", role)
	}
	return nil
}

func validOpaqueStageCorrelation(value string) bool {
	if value == "" || len(value) > 256 {
		return false
	}
	for _, r := range value {
		if unicode.IsControl(r) {
			return false
		}
	}
	return true
}

func (in hotPathStageInput) prompt(phase hotPathLightPhase) (string, error) {
	if err := in.validate(); err != nil {
		return "", err
	}
	if in.Role == "local" {
		return in.Artifacts.PlanPath + "\nRead it and complete the task.", nil
	}
	var b strings.Builder
	b.WriteString("User task:\n")
	b.WriteString(in.ImmutableTask)
	writeStageCorrelation(&b, "selector", in.SelectorCommit)
	if in.Role == "review" {
		writeStageCorrelation(&b, "local", in.LocalCommit)
	}
	b.WriteString("\n\nIssued workspace artifacts:\n- plan: ")
	b.WriteString(in.Artifacts.PlanPath)
	b.WriteString("\n- review: ")
	b.WriteString(in.Artifacts.ReviewPath)
	b.WriteString("\n\n")

	switch in.Role {
	case "review":
		switch phase {
		case hotPathPhaseReviewActive:
			b.WriteString("Read both exact issued PLAN and REVIEW artifacts. Inspect at least one actual caller-workspace result with an ordinary caller tool. Do not rewrite REVIEW. If the work is correct, return a concise non-empty final result without a tool call. If repair is needed, use ordinary caller tools to repair and re-verify in this same review stage.")
		case hotPathPhaseReviewRepair:
			b.WriteString("Continue the same review-stage repair and verification with ordinary caller tools. Do not read or rewrite the reserved artifacts again. When finished, return a concise non-empty final result without a tool call.")
		default:
			return "", fmt.Errorf("review input cannot run in phase %q", phase)
		}
	default:
		return "", fmt.Errorf("unknown stage role %q", in.Role)
	}
	return b.String(), nil
}

type correlationPromptValue struct {
	StageID    string `json:"stage"`
	ResponseID string `json:"response"`
	RunID      string `json:"run"`
	ProviderID string `json:"provider"`
	Terminal   string `json:"terminal"`
}

// writeStageCorrelation appends an immutable predecessor-success correlation
// block to the prompt builder. Correlation values are provider-visible but
// never carry credentials, provider targets, workspace file contents, or
// prior internal prompts.
func writeStageCorrelation(b *strings.Builder, role string, correlation hotPathStageCorrelation) {
	fmt.Fprintf(b, "\nCommitted %s stage success:\n", role)
	encoded, err := json.Marshal(correlationPromptValue{
		StageID:    correlation.StageID,
		ResponseID: correlation.ResponseID,
		RunID:      correlation.RunID,
		ProviderID: correlation.ProviderID,
		Terminal:   correlation.Terminal,
	})
	if err != nil {
		return
	}
	b.Write(encoded)
	b.WriteString("\n")
}
