package cli

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"sort"
	"strings"
	"time"

	"github.com/Clyra-AI/wrkr/core/evidence"
	"github.com/Clyra-AI/wrkr/core/state"
)

func runEvidence(args []string, stdout io.Writer, stderr io.Writer) int {
	jsonRequested := wantsJSONOutput(args)
	fs := flag.NewFlagSet("evidence", flag.ContinueOnError)
	if jsonRequested {
		fs.SetOutput(io.Discard)
	} else {
		fs.SetOutput(stderr)
	}

	jsonOut := fs.Bool("json", false, "emit machine-readable output")
	frameworksRaw := fs.String("frameworks", "", "comma-separated framework ids")
	outputDir := fs.String("output", "wrkr-evidence", "evidence output directory")
	statePathFlag := fs.String("state", "", "state file path override")

	if code, handled := parseFlags(fs, args, stderr, jsonRequested || *jsonOut); handled {
		return code
	}
	if fs.NArg() != 0 {
		return emitError(stderr, jsonRequested || *jsonOut, "invalid_input", "evidence does not accept positional arguments", exitInvalidInput)
	}
	frameworks := parseFrameworkFlags(*frameworksRaw)
	if len(frameworks) == 0 {
		return emitError(stderr, jsonRequested || *jsonOut, "invalid_input", "--frameworks is required", exitInvalidInput)
	}

	result, err := evidence.Build(evidence.BuildInput{
		StatePath:   *statePathFlag,
		Frameworks:  frameworks,
		OutputDir:   strings.TrimSpace(*outputDir),
		GeneratedAt: time.Now().UTC().Truncate(time.Second),
	})
	if err != nil {
		switch evidence.ClassifyBuildError(err) {
		case evidence.ErrorClassInvalidInput:
			return emitError(stderr, jsonRequested || *jsonOut, "invalid_input", err.Error(), exitInvalidInput)
		case evidence.ErrorClassUnsafeOperationBlocked:
			return emitError(stderr, jsonRequested || *jsonOut, "unsafe_operation_blocked", err.Error(), exitUnsafeBlocked)
		default:
			return emitError(stderr, jsonRequested || *jsonOut, "runtime_failure", err.Error(), exitRuntime)
		}
	}
	resolvedStatePath := state.ResolvePath(*statePathFlag)

	if *jsonOut {
		payload := map[string]any{
			"status":                 "ok",
			"deployment_mode":        result.DeploymentMode,
			"output_dir":             result.OutputDir,
			"frameworks":             result.Frameworks,
			"manifest_path":          result.ManifestPath,
			"artifact_manifest_path": result.ArtifactManifestPath,
			"chain_path":             result.ChainPath,
			"framework_coverage":     result.FrameworkCoverage,
			"control_evidence":       result.ControlEvidence,
			"coverage_note":          result.CoverageNote,
			"report_artifacts":       result.ReportArtifacts,
			"source_privacy":         result.SourcePrivacy,
			"agent_action_bom":       result.AgentActionBOM,
			"governed_usage_metrics": result.GovernedUsageMetrics,
			"next_steps":             evidenceNextSteps(resolvedStatePath, result.OutputDir, result.ManifestPath, result.ReportArtifacts),
		}
		if result.RuntimeEvidence != nil {
			payload["runtime_evidence"] = result.RuntimeEvidence
		}
		_ = json.NewEncoder(stdout).Encode(payload)
		return exitSuccess
	}
	_, _ = fmt.Fprintf(stdout, "wrkr evidence bundle written to %s\n", result.OutputDir)
	return exitSuccess
}

func parseFrameworkFlags(raw string) []string {
	set := map[string]struct{}{}
	for _, part := range strings.Split(raw, ",") {
		trimmed := strings.TrimSpace(part)
		if trimmed == "" {
			continue
		}
		set[trimmed] = struct{}{}
	}
	out := make([]string, 0, len(set))
	for value := range set {
		out = append(out, value)
	}
	// deterministic ordering in output and downstream evidence writes.
	sort.Strings(out)
	return out
}
