"""Requirement Analyst skill."""

from __future__ import annotations

from typing import List, Optional

from packages.artifacts.requirements import RequirementsArtifact
from packages.integrations.jira import JiraIssue
from packages.integrations.llm import LLMClient, get_llm_client
from packages.integrations.sanitize import sanitize_text
from packages.knowledge.retrievers import KnowledgeHit, KnowledgeService


class RequirementAnalyst:
    def __init__(
        self,
        llm: Optional[LLMClient] = None,
        knowledge: Optional[KnowledgeService] = None,
    ) -> None:
        self.llm = llm or get_llm_client()
        self.knowledge = knowledge or KnowledgeService()

    async def analyze(self, issue: JiraIssue) -> RequirementsArtifact:
        query = f"{issue.summary} {issue.description}"
        hits = await self.knowledge.gather(query, limit=5)
        prompt = build_analyst_prompt(issue, hits)
        artifact = await self.llm.analyze_requirements(prompt)
        # Ensure key is always from the issue
        artifact.jira_key = issue.key
        if not artifact.summary:
            artifact.summary = issue.summary
        # Guardrail: OpenAI often nags on non-blocking scope details even when AC is implementable.
        if (
            not artifact.is_clear
            and len(artifact.acceptance_criteria) >= 2
            and (artifact.confidence or 0) >= 0.7
            and issue.comments
        ):
            artifact.is_clear = True
            artifact.clarification_questions = []
            artifact.notes = (artifact.notes or "") + " | Auto-cleared after human comments (non-blocking gaps)."
        return artifact


def build_analyst_prompt(issue: JiraIssue, hits: List[KnowledgeHit]) -> str:
    ac = issue.acceptance_criteria or []
    comments = "\n".join(
        f"- {c.get('author')}: {sanitize_text(str(c.get('body') or ''))}" for c in issue.comments[-10:]
    )
    attachments = ", ".join(a.get("filename") or a.get("id") or "?" for a in issue.attachments) or "(none)"
    conf_hits = [h for h in hits if h.source == "confluence"]
    repo_hits = [h for h in hits if h.source == "git"]

    def fmt(hs: List[KnowledgeHit]) -> str:
        if not hs:
            return "(none)"
        return "\n".join(f"- {h.title}: {h.snippet}" for h in hs)

    return f"""You are the Requirement Analyst for Agent Nova (Salesforce development automation).
Decide if the Jira requirement is clear enough to implement allowlisted Salesforce metadata.

Clarity rules (follow strictly):
- Set is_clear=true when the story identifies the target object, what metadata to create/change, and the expected behavior — OR has explicit acceptance criteria covering those.
- Prefer reasonable defaults over questions for minor scope details (which layouts, record types, profiles, naming style, docs/training).
- Only set is_clear=false for true blockers: missing object, no concrete change, no behavior/AC, or conflicting requirements.
- If Comments contain human answers, treat them as locked decisions. Do not re-ask the same or equivalent questions; set is_clear=true unless a real blocker remains.
- Never invent acceptance criteria that are not present or clearly stated in comments.
- When is_clear=true, clarification_questions MUST be an empty list.

Jira key: {issue.key}
Summary: {sanitize_text(issue.summary)}
Status: {issue.status}
Labels: {', '.join(issue.labels)}

Description:
{sanitize_text(issue.description)}

Acceptance criteria:
{chr(10).join('- ' + sanitize_text(a) for a in ac) if ac else '(none provided — extract from Description if present)'}

Comments:
{comments or '(none)'}

Attachments: {attachments}

Confluence hits:
{fmt(conf_hits)}

Repository hits:
{fmt(repo_hits)}

v1 allowlist: custom fields, validation rules, record-triggered Flows, Apex classes/triggers, LWCs, permission sets.
Out of scope: production deploy, merge, sharing/OWD redesign, destructive deletes.
"""
