package capdiag

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

// RenderText formats a human-readable report: Summary → Issues → subsystems.
func RenderText(r Report) string {
	var b strings.Builder
	fmt.Fprintf(&b, "reasonix doctor capabilities\n")
	fmt.Fprintf(&b, "root: %s  live: %v  schema: %d\n\n", r.Root, r.Live, r.SchemaVersion)

	fmt.Fprintf(&b, "Summary\n")
	fmt.Fprintf(&b, "  errors=%d warnings=%d infos=%d\n", r.Summary.Errors, r.Summary.Warnings, r.Summary.Infos)
	fmt.Fprintf(&b, "  instructions=%d skills=%d commands=%d hooks=%d plugins=%d mcp=%d\n\n",
		r.Summary.Instructions, r.Summary.Skills, r.Summary.Commands,
		r.Summary.Hooks, r.Summary.Plugins, r.Summary.MCPServers)

	fmt.Fprintf(&b, "Issues (%d)\n", len(r.Issues))
	if len(r.Issues) == 0 {
		b.WriteString("  (none)\n")
	}
	for _, is := range r.Issues {
		fmt.Fprintf(&b, "  [%s] %s", is.Severity, is.Code)
		if is.Name != "" {
			fmt.Fprintf(&b, " %s", is.Name)
		}
		fmt.Fprintf(&b, ": %s\n", is.Message)
		if is.Source != "" {
			fmt.Fprintf(&b, "    source: %s\n", is.Source)
		}
		if is.Remediation != "" {
			fmt.Fprintf(&b, "    fix: %s\n", is.Remediation)
		}
	}
	b.WriteByte('\n')

	// Instructions
	fmt.Fprintf(&b, "Instructions (%d)\n", len(r.Instructions.Docs))
	for _, d := range r.Instructions.Docs {
		fmt.Fprintf(&b, "  %d. [%s depth=%d] %s", d.Order, d.Scope, d.Depth, d.Path)
		if d.Directory != "" {
			fmt.Fprintf(&b, " (applies to %s)", d.Directory)
		}
		b.WriteByte('\n')
	}
	if len(r.Instructions.Docs) == 0 {
		b.WriteString("  (none)\n")
	}
	b.WriteByte('\n')

	writeAsset(&b, "Skills", r.Skills)
	writeAsset(&b, "Commands", r.Commands)

	fmt.Fprintf(&b, "Hooks (project_defines=%v entries=%d)\n",
		r.Hooks.ProjectDefines, len(r.Hooks.Entries))
	for _, s := range r.Hooks.Sources {
		fmt.Fprintf(&b, "  source [%s] %s status=%s hooks=%d\n", s.Scope, s.Path, s.Status, s.HookCount)
	}
	for _, e := range r.Hooks.Entries {
		fmt.Fprintf(&b, "  - %s scope=%s match=%q blocking=%v\n", e.Event, e.Scope, e.Match, e.Blocking)
	}
	b.WriteByte('\n')

	fmt.Fprintf(&b, "Plugins (%d)\n", len(r.Plugins.Packages))
	for _, p := range r.Plugins.Packages {
		fmt.Fprintf(&b, "  - %s enabled=%v status=%s skills=%d commands=%d prompts=%d hooks=%d mcp=%d themes=%d\n",
			p.Name, p.Enabled, p.Status, p.Skills, p.Commands, p.Prompts, p.Hooks, p.MCPServers, p.Themes)
		if p.Runtime {
			b.WriteString("    runtime: FULL TRUST (declares a runtime process)\n")
		}
		fmt.Fprintf(&b, "    root: %s\n", p.Root)
	}
	if len(r.Plugins.Packages) == 0 {
		b.WriteString("  (none)\n")
	}
	b.WriteByte('\n')

	fmt.Fprintf(&b, "MCP (%d)\n", len(r.MCP.Servers))
	for _, s := range r.MCP.Servers {
		fmt.Fprintf(&b, "  - %s transport=%s intent=%s source=%s effective=%v", s.Name, s.Transport, s.StartIntent, s.Source, s.Effective)
		if s.RuntimeStatus != "" {
			fmt.Fprintf(&b, " runtime=%s", s.RuntimeStatus)
		}
		if s.ToolCount > 0 {
			fmt.Fprintf(&b, " tools=%d", s.ToolCount)
		}
		b.WriteByte('\n')
		if s.SourcePath != "" {
			fmt.Fprintf(&b, "    source_path: %s\n", s.SourcePath)
		}
		if s.StartupStage != "" {
			fmt.Fprintf(&b, "    startup: stage=%s elapsed_ms=%d\n", s.StartupStage, s.StartupElapsedMS)
		}
		if s.Error != "" {
			fmt.Fprintf(&b, "    error: %s\n", s.Error)
		}
		if s.Stderr != "" {
			fmt.Fprintf(&b, "    stderr: %s\n", s.Stderr)
		}
	}
	if len(r.MCP.Servers) == 0 {
		b.WriteString("  (none)\n")
	}
	return b.String()
}

func writeAsset(b *strings.Builder, title string, a AssetReport) {
	fmt.Fprintf(b, "%s (winners=%d shadowed=%d", title, a.Winners, a.Shadowed)
	if a.Disabled > 0 {
		fmt.Fprintf(b, " disabled=%d", a.Disabled)
	}
	if a.ParseErrors > 0 {
		fmt.Fprintf(b, " errors=%d", a.ParseErrors)
	}
	b.WriteString(")\n")
	for _, r := range a.Roots {
		fmt.Fprintf(b, "  root %s status=%s", r.Path, r.Status)
		if r.Scope != "" {
			fmt.Fprintf(b, " scope=%s", r.Scope)
		}
		b.WriteByte('\n')
	}
	for _, e := range a.Entries {
		if e.Status != "winner" && e.Status != "error" {
			continue // keep text output compact; full list is in JSON
		}
		fmt.Fprintf(b, "  - %s [%s] %s\n", e.Name, e.Status, e.Path)
	}
	b.WriteByte('\n')
}

// RenderJSON writes indented JSON to a string (for tests / copy).
func RenderJSON(r Report) (string, error) {
	b, err := json.MarshalIndent(r, "", "  ")
	if err != nil {
		return "", err
	}
	return string(b) + "\n", nil
}
