package graphbuilder

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/tidbcloud/AgentTeam/kits/agentteam-insight/internal/graphbuilder/persistence"
	"github.com/tidbcloud/AgentTeam/kits/agentteam-insight/internal/graphbuilder/schema"
	"github.com/tidbcloud/AgentTeam/kits/agentteam-insight/internal/graphbuilder/semantic"
)

// DomainResult describes one knowledge-graph to domain-graph conversion.
type DomainResult struct {
	GraphPath string
	Nodes     int
	Edges     int
}

// RunDomain derives domain-graph.json from an existing knowledge-graph.json
// with exactly one invocation of the same semantic runner used by Run.
func RunDomain(ctx context.Context, options Options, runner CommandRunner) (DomainResult, error) {
	if runner == nil {
		return DomainResult{}, fmt.Errorf("command runner is required")
	}
	normalized, err := normalizeOptions(options)
	if err != nil {
		return DomainResult{}, err
	}
	if err := ctx.Err(); err != nil {
		return DomainResult{}, err
	}
	layout, err := persistence.ResolveLayout(normalized.InputRepo, normalized.OutputRoot)
	if err != nil {
		return DomainResult{}, err
	}
	logger := newProgressLogger(normalized.ProgressWriter)
	logger.Printf("loading knowledge graph: %s", layout.GraphPath)
	store := persistence.NewStoreWithLayout(layout)
	graph, err := store.LoadGraph(true)
	if err != nil {
		return DomainResult{}, fmt.Errorf("load %s: %w", persistence.GraphFileName, err)
	}
	if graph == nil {
		return DomainResult{}, fmt.Errorf("%s is required; run agentteam-insight graph first", layout.GraphPath)
	}
	logger.Printf("knowledge graph validated: nodes=%d edges=%d", len(graph.Nodes), len(graph.Edges))
	graphJSON, err := json.MarshalIndent(graph, "", "  ")
	if err != nil {
		return DomainResult{}, fmt.Errorf("encode %s: %w", persistence.GraphFileName, err)
	}

	semanticRunner := normalized.SemanticRunner
	if semanticRunner == nil {
		normalized.IsolateOpenCodeRuntime = true
		semanticRunner = opencodeFileAnalyzerRunner{
			options: normalized,
			layout:  layout,
			runner:  runner,
			logger:  logger,
		}
	}
	const inputFile = ".ua/intermediate/knowledge-graph.json"
	logger.Printf("starting domain analysis with one LLM invocation")
	output, err := semanticRunner.Invoke(ctx, semantic.Invocation{
		Stage:      semantic.Domain,
		Attempt:    1,
		Prompt:     semantic.BuildDomainPrompt(layout.ProjectRoot, inputFile, normalized.OutputLanguage),
		OutputFile: ".ua/intermediate/domain-analysis.json",
		InputFile:  inputFile,
		Input:      graphJSON,
	})
	if err != nil {
		return DomainResult{}, err
	}
	logger.Printf("domain analysis completed; validating generated graph")
	validated := schema.ValidateGraphJSON(output)
	if !validated.Success || validated.Data == nil {
		return DomainResult{}, fmt.Errorf("validate domain graph: %s", firstNonEmpty(validated.Fatal, "invalid graph"))
	}
	if err := schema.ValidateDomainGraph(*validated.Data); err != nil {
		return DomainResult{}, fmt.Errorf("validate domain graph: %w", err)
	}
	logger.Printf("domain graph validated: nodes=%d edges=%d", len(validated.Data.Nodes), len(validated.Data.Edges))
	logger.Printf("writing domain graph: %s", layout.DomainGraphPath)
	if err := store.SaveDomainGraph(*validated.Data); err != nil {
		return DomainResult{}, err
	}
	logger.Printf("domain graph written: %s", layout.DomainGraphPath)
	return DomainResult{GraphPath: layout.DomainGraphPath, Nodes: len(validated.Data.Nodes), Edges: len(validated.Data.Edges)}, nil
}
