package runner

import "strings"

const (
	workflowGuideValidationBoundaries = "read-only routing report; uses runner-owned heuristic guidance only; does not inspect documents, query storage, fetch URLs, create candidates, create or update documents, repair synthesis, or bypass installed openclerk document/retrieval JSON"
	workflowGuideAuthorityLimits      = "this report routes workflow surface choice only; final answers and source-sensitive claims must come from the selected runner action result, citations, provenance, projection freshness, validation boundaries, and authority limits"
)

func runWorkflowGuideReport(options WorkflowGuideOptions) WorkflowGuideReport {
	intent := strings.TrimSpace(options.Intent)
	selected := selectWorkflowGuideCandidate(intent)
	report := WorkflowGuideReport{
		Intent:               intent,
		RecommendedSurface:   selected.Surface,
		RunnerDomain:         selected.RunnerDomain,
		RequestShape:         selected.RequestShape,
		UseWhen:              selected.UseWhen,
		DoNotUseFor:          selected.DoNotUseFor,
		CandidateSurfaces:    workflowGuideCandidates(),
		ValidationBoundaries: workflowGuideValidationBoundaries,
		AuthorityLimits:      workflowGuideAuthorityLimits,
	}
	report.AgentHandoff = &AgentHandoff{
		AnswerSummary:               selected.HandoffSummary,
		Evidence:                    []string{"intent:" + intent, "recommended_surface:" + selected.Surface, "runner_domain:" + selected.RunnerDomain},
		ValidationBoundaries:        report.ValidationBoundaries,
		AuthorityLimits:             report.AuthorityLimits,
		FollowUpPrimitiveInspection: "Run the recommended openclerk document or retrieval request next; use lower-level primitives only for explicit advanced/manual work or after a runner rejection.",
	}
	return report
}

type workflowGuideSelection struct {
	Surface        string
	RunnerDomain   string
	RequestShape   string
	UseWhen        string
	DoNotUseFor    []string
	HandoffSummary string
}

func selectWorkflowGuideCandidate(intent string) workflowGuideSelection {
	normalized := strings.ToLower(intent)
	switch {
	case containsAny(normalized, "representative source", "source discovery", "find sources", "source categories", "representative sources"):
		return workflowGuideSelection{
			Surface:        "source_discovery_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"source_discovery_report","source_discovery":{"query":"...","limit":10}}`,
			UseWhen:        "use for read-only representative source discovery and sanitized source-category summaries",
			DoNotUseFor:    []string{"durable writes", "raw private content exposure", "external search"},
			HandoffSummary: "Use retrieval source_discovery_report, then answer from source_discovery.agent_handoff without private paths, titles, snippets, ids, or raw JSON.",
		}
	case containsAny(normalized, "public url", "public link", "source url", "fetch url", "ingest url", "web page", "pdf url", "public pdf"):
		return workflowGuideSelection{
			Surface:        "ingest_source_url inspect",
			RunnerDomain:   "document",
			RequestShape:   `{"action":"ingest_source_url","source":{"url":"https://example.test/page.html","mode":"inspect","source_type":"web","title":"Optional title","limit":8}}`,
			UseWhen:        "use for read-only inspection of a supplied public URL plus related source candidates before durable write approval",
			DoNotUseFor:    []string{"login-gated pages", "purchases", "captcha/paywall bypasses", "non-runner HTTP/browser fetch"},
			HandoffSummary: "Use document ingest_source_url with mode inspect for public-link exploration; public read/fetch permission is separate from durable-write approval.",
		}
	case containsAny(normalized, "artifact", "invoice", "receipt", "legal document", "transcript", "auto-file", "autofile", "candidate path", "body preview", "metadata field", "tags", "ocr", "scan-only", "scanned pdf", "local file"):
		return workflowGuideSelection{
			Surface:        "artifact_candidate_plan",
			RunnerDomain:   "document",
			RequestShape:   `{"action":"artifact_candidate_plan","artifact":{"content":"...","artifact_kind":"note","tags":["..."],"fields":{"type":"note"},"limit":5}} or {"action":"artifact_candidate_plan","artifact":{"local_path":"<explicit-user-local-file>","artifact_kind":"receipt","text_extraction":"ocr_review","ocr_provider":"tesseract","limit":5}}`,
			UseWhen:        "use for read-only candidate path/title/body preview/tag/field planning from explicit content, supported explicit local files, explicit OCR review, or public-source handoff context",
			DoNotUseFor:    []string{"opaque file parsing", "implicit local file reads", "external OCR", "durable document writes", "private or authenticated acquisition"},
			HandoffSummary: "Use document artifact_candidate_plan for proposal-first intake; approved writes still flow through create_document or ingest_source_url.",
		}
	case containsAny(normalized, "duplicate", "already exists", "update existing", "update versus new", "same note"):
		return workflowGuideSelection{
			Surface:        "duplicate_candidate_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"duplicate_candidate_report","duplicate_candidate":{"query":"...","path_prefix":"notes/","limit":10}}`,
			UseWhen:        "use before choosing update versus new for plausible duplicate document requests",
			DoNotUseFor:    []string{"durable document writes", "unrelated source-sensitive audits"},
			HandoffSummary: "Use retrieval duplicate_candidate_report, then answer from duplicate_candidate.agent_handoff before asking for durable-write approval.",
		}
	case containsAny(normalized, "web search", "search web", "search-to-source", "search to source", "search results"):
		return workflowGuideSelection{
			Surface:        "web_search_plan",
			RunnerDomain:   "document",
			RequestShape:   `{"action":"web_search_plan","web_search":{"query":"...","results":[{"url":"https://example.test/page.html","title":"Example","snippet":"..."}],"limit":10}}`,
			UseWhen:        "use for harness-supplied public web search results before selecting an ingest_source_url candidate",
			DoNotUseFor:    []string{"live search provider calls", "browser automation", "durable fetch/write", "private or authenticated pages"},
			HandoffSummary: "Use document web_search_plan for read-only search-result planning; approved public fetch/write still flows through ingest_source_url.",
		}
	case containsAny(normalized, "source placement", "pdf"):
		return workflowGuideSelection{
			Surface:        "ingest_source_url plan",
			RunnerDomain:   "document",
			RequestShape:   `{"action":"ingest_source_url","source":{"url":"https://example.test/page.html","mode":"plan","source_type":"web","title":"Optional title"}}`,
			UseWhen:        "use for no-fetch public URL source placement before durable fetch or write approval",
			DoNotUseFor:    []string{"login-gated pages", "purchases", "captcha/paywall bypasses", "non-runner HTTP/browser fetch"},
			HandoffSummary: "Use document ingest_source_url with mode plan for public-link placement; public read/fetch permission is separate from durable-write approval.",
		}
	case containsAny(normalized, "validation synthesis", "disposable synthesis", "routine ux validation"):
		return workflowGuideSelection{
			Surface:        "validation_synthesis_report",
			RunnerDomain:   "document",
			RequestShape:   `{"action":"validation_synthesis_report","validation_synthesis":{"disposable_validation":true,"body_facts":["..."]}}`,
			UseWhen:        "use for routine UX disposable validation synthesis create/update workflows where validation defaults may be used safely",
			DoNotUseFor:    []string{"live-vault durable writes", "uncited claims", "non-validation synthesis"},
			HandoffSummary: "Use document validation_synthesis_report for disposable validation synthesis, then answer from validation_synthesis.agent_handoff.",
		}
	case containsAny(normalized, "synthesis", "compile", "summarize sources", "source-linked answer", "file answer"):
		return workflowGuideSelection{
			Surface:        "compile_synthesis",
			RunnerDomain:   "document",
			RequestShape:   `{"action":"compile_synthesis","synthesis":{"path":"synthesis/example.md","title":"Example","source_refs":["sources/a.md"],"body_facts":["..."],"mode":"create_or_update"}}`,
			UseWhen:        "use for approved source-linked synthesis create/update",
			DoNotUseFor:    []string{"uncited claims", "duplicate synthesis creation", "unapproved durable writes"},
			HandoffSummary: "Use document compile_synthesis for approved source-linked synthesis, then answer from final_answer, agent_handoff, or compile_synthesis.agent_handoff.",
		}
	case containsAny(normalized, "git", "checkpoint", "version history", "storage history", "local history"):
		return workflowGuideSelection{
			Surface:        "git_lifecycle_report",
			RunnerDomain:   "document",
			RequestShape:   `{"action":"git_lifecycle_report","git_lifecycle":{"mode":"status","paths":["synthesis/example.md"],"limit":10}}`,
			UseWhen:        "use for local Git status/history metadata or explicit local checkpoints around approved OpenClerk-authored durable writes",
			DoNotUseFor:    []string{"restore", "rollback", "branch switching", "remote push", "semantic provenance replacement"},
			HandoffSummary: "Use document git_lifecycle_report for storage-level status/history; checkpoint mode requires explicit runner config and never replaces provenance/freshness evidence.",
		}
	case containsAny(normalized, "source audit", "conflict", "contradiction", "stale source", "repair synthesis"):
		return workflowGuideSelection{
			Surface:        "source_audit_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"source_audit_report","source_audit":{"query":"...","target_path":"synthesis/example.md","mode":"explain","limit":10}}`,
			UseWhen:        "use for source-sensitive audit explanation or approved existing-target repair",
			DoNotUseFor:    []string{"broad contradiction engine", "new synthesis creation"},
			HandoffSummary: "Use retrieval source_audit_report; explain mode is read-only, repair_existing may update only an existing synthesis target.",
		}
	case containsAny(normalized, "memory router", "memory-router", "router policy", "stale session", "feedback weighting", "temporal recall"):
		return workflowGuideSelection{
			Surface:        "memory_router_recall_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"memory_router_recall_report","memory_router_recall":{"query":"...","limit":10}}`,
			UseWhen:        "use for read-only memory-router policy evidence such as stale-session posture, temporal policy, feedback weighting, and routing rationale",
			DoNotUseFor:    []string{"ordinary vault fact recall", "remember/recall transports", "autonomous router APIs", "memory writes"},
			HandoffSummary: "Use retrieval memory_router_recall_report only for memory-router policy evidence; use retrieval search for ordinary vault fact recall.",
		}
	case containsAny(normalized, "structured", "canonical store", "time-series", "time series", "metrics", "measurements", "inventory", "finance", "health"):
		return workflowGuideSelection{
			Surface:        "structured_store_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"structured_store_report","structured_store":{"domain":"records","query":"...","limit":10}}`,
			UseWhen:        "use for structured-data and non-document canonical-store decision support",
			DoNotUseFor:    []string{"independent canonical tables", "external store connectors", "durable structured writes"},
			HandoffSummary: "Use retrieval structured_store_report and answer from structured_store.agent_handoff.",
		}
	case containsAny(normalized, "hybrid", "vector", "embedding", "semantic retrieval"):
		return workflowGuideSelection{
			Surface:        "hybrid_retrieval_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"hybrid_retrieval_report","hybrid_retrieval":{"query":"...","path_prefix":"docs/","limit":10}}`,
			UseWhen:        "use for read-only hybrid/vector retrieval decision support",
			DoNotUseFor:    []string{"vector-ranked answers", "embedding-store evidence", "default ranking changes"},
			HandoffSummary: "Use retrieval hybrid_retrieval_report and do not claim vector-ranked retrieval from it.",
		}
	case containsAny(normalized, "search diagnostics", "search mode", "tuning", "which search", "semantic_search readiness", "module readiness"):
		return workflowGuideSelection{
			Surface:        "search_diagnostics_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"search_diagnostics_report","search_diagnostics":{"query":"...","intent":"...","limit":10,"provider":"ollama"}}`,
			UseWhen:        "use for read-only search versus explicit semantic_search selection, tuning visibility, and provider/module readiness posture",
			DoNotUseFor:    []string{"answering source-sensitive questions", "executing semantic modules", "default ranking changes"},
			HandoffSummary: "Use retrieval search_diagnostics_report to choose search versus explicit semantic_search; then run the recommended retrieval action for evidence.",
		}
	case containsAny(normalized, "retrieval eval", "eval capture", "retrieval replay", "replay search", "regression test retrieval"):
		return workflowGuideSelection{
			Surface:        "retrieval_eval_capture/retrieval_eval_replay",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"retrieval_eval_capture","retrieval_eval":{"action":"search","search":{"text":"...","limit":10}}} then {"action":"retrieval_eval_replay","retrieval_replay":{"limit":100}}`,
			UseWhen:        "use for explicit local-only sanitized retrieval regression capture and replay",
			DoNotUseFor:    []string{"document writes", "raw vault content capture", "background eval jobs", "default ranking changes"},
			HandoffSummary: "Use retrieval_eval_capture only when explicitly requested, and retrieval_eval_replay after retrieval changes to compare Jaccard/top-1/latency.",
		}
	case containsAny(normalized, "maintenance", "doctor", "health report", "maintenance report"):
		return workflowGuideSelection{
			Surface:        "maintenance_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"maintenance_report","maintenance":{"query":"...","path_prefix":"notes/","limit":20}}`,
			UseWhen:        "use for a read-only doctor report across layout, projection freshness, relationship context, duplicate risk, module posture, and git lifecycle posture",
			DoNotUseFor:    []string{"repairs", "cron/background jobs", "autonomous writes"},
			HandoffSummary: "Use retrieval maintenance_report for consolidated read-only posture, then follow up with named runner actions and approved writes only where needed.",
		}
	case containsAny(normalized, "decision-like", "decision like", "decision record", "decision lookup", "adr lookup"):
		return workflowGuideSelection{
			Surface:        "decision_lookup_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"decision_lookup_report","decision_lookup":{"query":"...","limit":10}}`,
			UseWhen:        "use for natural decision-like record lookup across formal decisions, promoted records, search evidence, provenance, and projection freshness",
			DoNotUseFor:    []string{"durable writes", "hidden authority ranking"},
			HandoffSummary: "Use retrieval decision_lookup_report, then answer from decision_lookup.agent_handoff.",
		}
	case containsAny(normalized, "record", "records", "decision", "provenance", "projection", "evidence bundle", "freshness"):
		return workflowGuideSelection{
			Surface:        "evidence_bundle_report",
			RunnerDomain:   "retrieval",
			RequestShape:   `{"action":"evidence_bundle_report","evidence_bundle":{"query":"...","projection":"records","limit":10}}`,
			UseWhen:        "use for records, decisions, provenance, projection freshness, and citation evidence bundles",
			DoNotUseFor:    []string{"durable writes", "memory transport", "hidden ranking"},
			HandoffSummary: "Use retrieval evidence_bundle_report, then answer from evidence_bundle.agent_handoff.",
		}
	default:
		return workflowGuideSelection{
			Surface:        "current_primitives_or_runner_help",
			RunnerDomain:   "document/retrieval",
			RequestShape:   `{"action":"search","search":{"text":"...","limit":10}}`,
			UseWhen:        "use openclerk document --help or openclerk retrieval --help, then choose primitives for explicit manual or unsupported promoted workflow requests",
			DoNotUseFor:    []string{"bypass workflows", "durable writes without approval"},
			HandoffSummary: "Use compact runner help and current primitives; do not expand SKILL.md with a long recipe for this intent.",
		}
	}
}

func containsAny(value string, needles ...string) bool {
	for _, needle := range needles {
		if strings.Contains(value, needle) {
			return true
		}
	}
	return false
}

func workflowGuideCandidates() []WorkflowGuideCandidate {
	return []WorkflowGuideCandidate{
		{
			Surface:        "current_primitives_or_runner_help",
			Status:         "keep_for_manual_or_advanced",
			SelectionRule:  "use when no promoted action matches, after runner rejection, or when the user explicitly asks for primitives",
			Boundary:       "do not repair routine UX by adding long SKILL.md recipes",
			RequestExample: `{"action":"search","search":{"text":"authority evidence","limit":10}}`,
		},
		{
			Surface:        "existing_natural_runner_action",
			Status:         "prefer_when_input_belongs_to_existing_action",
			SelectionRule:  "use when an adjacent mode on an existing action preserves the natural workflow surface",
			Boundary:       "public read/fetch/inspect permission is separate from durable-write approval",
			RequestExample: `{"action":"ingest_source_url","source":{"url":"https://example.test/page.html","mode":"inspect","source_type":"web","limit":8}}`,
		},
		{
			Surface:        "artifact_candidate_plan",
			Status:         "promoted_for_artifact_intake_planning",
			SelectionRule:  "use when explicit artifact content or public-source handoff context needs candidate path, title, body preview, tags, fields, confidence, and duplicate evidence before approval",
			Boundary:       "read-only planning only; local file inspection only through explicit artifact.local_path and limited text/PDF parsers, or explicit OCR review through an installed verified local OCR module; no opaque parsing, fetches, or durable writes",
			RequestExample: `{"action":"artifact_candidate_plan","artifact":{"content":"...","artifact_kind":"receipt","tags":["finance"],"limit":5}}`,
		},
		{
			Surface:        "promoted_workflow_action_with_agent_handoff",
			Status:         "prefer_for_repeated_routine_workflows",
			SelectionRule:  "use when current primitives are safe but too ceremonial, scripted, slow, or guidance-dependent",
			Boundary:       "must preserve citations, provenance, freshness, duplicate handling, local-first runner-only access, and approval-before-write",
			RequestExample: `{"action":"duplicate_candidate_report","duplicate_candidate":{"query":"...","limit":10}}`,
		},
		{
			Surface:        "source_discovery_report",
			Status:         "promoted_for_representative_source_discovery",
			SelectionRule:  "use when a user asks to find representative sources or source categories without needing raw private content",
			Boundary:       "read-only source discovery; final answers should summarize categories and counts when private-vault telemetry asks for sanitization",
			RequestExample: `{"action":"source_discovery_report","source_discovery":{"query":"...","limit":10}}`,
		},
		{
			Surface:        "decision_lookup_report",
			Status:         "promoted_for_decision_like_lookup",
			SelectionRule:  "use when decision-like evidence may live across formal decisions, promoted records, provenance, projection, and source search evidence",
			Boundary:       "read-only; canonical markdown remains authority and projections are derived evidence",
			RequestExample: `{"action":"decision_lookup_report","decision_lookup":{"query":"...","limit":10}}`,
		},
		{
			Surface:       "skill_recipe_expansion",
			Status:        "avoid",
			SelectionRule: "do not choose unless it is a compact safety bridge or action index entry for an already-promoted surface",
			Boundary:      "long request examples, field catalogs, and exact command choreography belong in runner help, reports, docs, or evals",
		},
	}
}
