"""Reunify module - aggregation, merge generation, and adversarial review."""

from __future__ import annotations

from datetime import datetime
from pathlib import Path

from cleave.core.conflicts import Conflict, detect_conflicts, parse_task_result


def aggregate_results(result_paths: list[str]) -> dict:
    """Aggregate results from all child tasks.

    Collects:
    - All file claims (artifacts)
    - All interfaces published
    - All decisions made
    - All assumptions
    - Status rollup (SUCCESS only if all SUCCESS)
    """
    results = [parse_task_result(path) for path in result_paths]

    aggregated: dict = {
        "task_count": len(results),
        "statuses": {},
        "all_files": [],
        "all_interfaces": [],
        "all_decisions": [],
        "all_assumptions": [],
        "verification_summary": [],
        "by_task": [],
    }

    for i, result in enumerate(results):
        status = result.get("status", "PENDING")
        aggregated["statuses"][status] = aggregated["statuses"].get(status, 0) + 1
        aggregated["all_files"].extend(result.get("file_claims", []))
        aggregated["all_interfaces"].extend(result.get("interfaces_published", []))
        aggregated["all_decisions"].extend(result.get("decisions", []))
        aggregated["all_assumptions"].extend(result.get("assumptions", []))

        # Collect verification info
        verification = result.get("verification", {})
        aggregated["verification_summary"].append(
            {
                "task_id": i,
                "command": verification.get("command"),
                "output": verification.get("output"),
                "coverage": verification.get("coverage"),
                "edge_cases": verification.get("edge_cases", []),
                "has_verification": verification.get("command") is not None,
            }
        )

        aggregated["by_task"].append(
            {
                "id": i,
                "path": result.get("path", f"task-{i}"),
                "status": status,
                "summary": result.get("summary"),
                "file_count": len(result.get("file_claims", [])),
                "interface_count": len(result.get("interfaces_published", [])),
                "verified": verification.get("command") is not None,
                "alignment": result.get("alignment", {}),
            }
        )

    # Deduplicate
    aggregated["all_files"] = list(set(aggregated["all_files"]))
    aggregated["all_interfaces"] = list(set(aggregated["all_interfaces"]))

    # Compute rollup status
    statuses = [r.get("status") for r in results]
    if all(s == "SUCCESS" for s in statuses):
        aggregated["rollup_status"] = "SUCCESS"
    elif any(s == "FAILED" for s in statuses):
        aggregated["rollup_status"] = "FAILED"
    elif any(s == "PARTIAL" for s in statuses):
        aggregated["rollup_status"] = "PARTIAL"
    else:
        aggregated["rollup_status"] = "PENDING"

    return aggregated


def generate_merge_md(conflicts: list[Conflict], aggregated: dict, workspace_path: str) -> str:
    """Generate merge.md content for conflict resolution.

    This file guides the human/Claude through resolving detected conflicts.
    """
    conflict_sections = []

    for i, conflict in enumerate(conflicts):
        resolution_guidance = {
            "file_overlap": "Review changes from both tasks. Use git diff or manual inspection to merge.",
            "decision_contradiction": "Escalate to parent intent. Which decision aligns better with root goal?",
            "interface_mismatch": "Create adapter or agree on single signature. Update consumers.",
            "assumption_violation": "Verify assumption against parent directive. One task may need rework.",
        }

        conflict_sections.append(
            f"""### Conflict {i + 1}: {conflict.type}

**Description:** {conflict.description}

**Involved Tasks:** {', '.join([f"Task {t}" for t in conflict.involved])}

**Resolution Strategy:** {conflict.resolution}

**Guidance:** {resolution_guidance.get(conflict.type, "Manual review required.")}

**Resolution:**
- [ ] Reviewed both tasks
- [ ] Resolution decided: [DESCRIBE]
- [ ] Changes applied
- [ ] Verified no new conflicts introduced
"""
        )

    conflicts_content = "\n".join(conflict_sections) if conflict_sections else "No conflicts detected."

    task_table = "\n".join(
        [
            f"| {t['id']} | {t['status']} | {t['file_count']} | {t['interface_count']} |"
            for t in aggregated["by_task"]
        ]
    )

    files_list = (
        "\n".join([f"- `{f}`" for f in aggregated["all_files"]])
        if aggregated["all_files"]
        else "- None recorded"
    )

    interfaces_list = (
        "\n".join([f"- `{i}`" for i in aggregated["all_interfaces"]])
        if aggregated["all_interfaces"]
        else "- None recorded"
    )

    decisions_list = (
        "\n".join([f"- {d}" for d in aggregated["all_decisions"]])
        if aggregated["all_decisions"]
        else "- None recorded"
    )

    assumptions_list = (
        "\n".join([f"- {a}" for a in aggregated["all_assumptions"]])
        if aggregated["all_assumptions"]
        else "- None recorded"
    )

    return f"""# Merge Resolution Guide

Generated: {datetime.now().isoformat()}
Workspace: {workspace_path}

## Summary

- **Tasks Reunified:** {aggregated['task_count']}
- **Rollup Status:** {aggregated['rollup_status']}
- **Conflicts Found:** {len(conflicts)}
- **Total Files Modified:** {len(aggregated['all_files'])}
- **Total Interfaces:** {len(aggregated['all_interfaces'])}

## Task Status

| Task | Status | Files | Interfaces |
|------|--------|-------|------------|
{task_table}

## Conflicts

{conflicts_content}

## Aggregated Artifacts

### Files Modified
{files_list}

### Interfaces Published
{interfaces_list}

### Decisions Made
{decisions_list}

### Assumptions
{assumptions_list}

## Reunification Checklist

- [ ] All conflicts resolved above
- [ ] Integration tests pass
- [ ] No regressions in existing functionality
- [ ] Documentation updated if needed
- [ ] Ready for parent task completion

## Notes

[Add any notes about the reunification process here]
"""


def generate_review_md(aggregated: dict, conflicts: list[Conflict], workspace_path: str) -> str:
    """Generate adversarial review checklist for post-reunification validation.

    This prompts systematic verification that:
    1. Each child's verification evidence is sufficient
    2. Integration points work together
    3. Edge cases are covered
    4. No gaps between child scopes
    """
    # Analyze verification coverage
    verified_count = sum(1 for v in aggregated["verification_summary"] if v["has_verification"])
    total_count = len(aggregated["verification_summary"])
    all_edge_cases = []
    for v in aggregated["verification_summary"]:
        all_edge_cases.extend(v.get("edge_cases", []))

    # Build verification status section
    verification_lines = []
    for v in aggregated["verification_summary"]:
        cmd = v["command"] or "[no verification provided]"
        output = v["output"] or "[no output]"
        verification_lines.append(
            f"""### Task {v['task_id']}
- Command: `{cmd}`
- Result: {output}
- Coverage: {v['coverage'] or 'N/A'}
- Edge cases: {', '.join(v['edge_cases']) if v['edge_cases'] else 'None listed'}
"""
        )

    verification_section = "\n".join(verification_lines)

    # Build integration probes
    interfaces = aggregated.get("all_interfaces", [])
    interface_probes = []
    if interfaces:
        for iface in interfaces[:5]:  # Limit to first 5
            interface_probes.append(f"- [ ] `{iface}` - called correctly by consumers?")

    interface_probes_str = (
        "\n".join(interface_probes)
        if interface_probes
        else "- [ ] No interfaces published - verify tasks produce expected outputs"
    )

    # Build task summaries section
    summary_lines = []
    for task in aggregated["by_task"]:
        summary = task.get("summary") or "[no summary provided]"
        alignment = task.get("alignment", {})
        aligns = alignment.get("aligns_with_goal", "?")
        violates = alignment.get("violates_constraints", "?")
        summary_lines.append(
            f"""### Task {task['id']}
- **Summary:** {summary}
- **Aligns with goal:** {aligns}
- **Violates constraints:** {violates}
"""
        )

    task_summaries = "\n".join(summary_lines)

    decisions_list = (
        "\n".join([f"- {d}" for d in aggregated["all_decisions"][:10]])
        if aggregated["all_decisions"]
        else "- None recorded"
    )

    edge_cases_list = (
        "\n".join([f"- {e}" for e in all_edge_cases[:10]])
        if all_edge_cases
        else "- None listed by children"
    )

    return f"""# Adversarial Review: {workspace_path}

**Purpose:** Systematic validation that reunified work actually functions as intended.

## Task Summaries

{task_summaries}

## Verification Evidence Summary

**Coverage:** {verified_count}/{total_count} tasks provided verification evidence

{verification_section}

## Integration Probes

Test that child outputs connect properly:

{interface_probes_str}

**Cross-cutting concerns:**
- [ ] Error handling: What happens when Task 0's output is invalid for Task 1?
- [ ] Edge cases: Are boundary conditions tested at integration points?
- [ ] Data flow: Does data pass correctly between components?

## Gap Analysis

**Questions to probe:**
- [ ] Is there functionality in the root intent not covered by any child?
- [ ] Do the children's scopes have overlaps or gaps?
- [ ] Are there implicit assumptions between siblings that aren't verified?

**Decisions made across tasks:**
{decisions_list}

**Do any decisions conflict or create inconsistency?**
- [ ] Reviewed - no conflicts
- [ ] Conflicts found: [describe]

## Functional Validation

**Run these commands to verify the reunified result:**

```bash
# TODO: Add integration test command
# TODO: Add build/compile command
# TODO: Add smoke test command
```

**Manual verification:**
- [ ] Core happy path works end-to-end
- [ ] Error cases handled gracefully
- [ ] Performance acceptable

## Edge Cases to Probe

From child task verification:
{edge_cases_list}

**Additional edge cases to test:**
- [ ] Empty/null inputs
- [ ] Maximum size inputs
- [ ] Concurrent access (if applicable)
- [ ] Network failures (if applicable)

## Review Outcome

- [ ] **PASS** - All probes satisfied, ready to close
- [ ] **NEEDS WORK** - Issues found (document below)
- [ ] **BLOCKED** - Cannot verify (explain why)

**Issues Found:**
[Document any problems discovered during review]

**Remediation Required:**
[List specific fixes needed]
"""


def reunify_workspace(
    workspace_path: str, write_merge: bool = True, write_review: bool = True
) -> dict:
    """Reunify all child tasks in a workspace.

    1. Finds all N-task.md files
    2. Parses and aggregates results
    3. Runs conflict detection
    4. Generates merge.md if conflicts exist or requested
    5. Generates review.md for adversarial validation (on by default)
    6. Returns unified summary
    """
    workspace = Path(workspace_path)

    if not workspace.exists():
        return {"error": f"Workspace not found: {workspace_path}"}

    # Find all task files (0-task.md, 1-task.md, etc.)
    task_files = sorted(
        workspace.glob("[0-9]*-task.md"), key=lambda p: int(p.name.split("-")[0])
    )

    if not task_files:
        return {"error": f"No task files found in {workspace_path}"}

    result_paths = [str(f) for f in task_files]

    # Aggregate results
    aggregated = aggregate_results(result_paths)

    # Detect conflicts
    conflicts = detect_conflicts(result_paths)

    # Generate merge.md if conflicts or explicitly requested
    merge_path = None
    if conflicts or write_merge:
        merge_content = generate_merge_md(conflicts, aggregated, workspace_path)
        merge_path = workspace / "merge.md"
        merge_path.write_text(merge_content)

    # Generate review.md for adversarial validation (on by default)
    review_path = None
    if write_review:
        review_content = generate_review_md(aggregated, conflicts, workspace_path)
        review_path = workspace / "review.md"
        review_path.write_text(review_content)

    # Compute verification coverage
    verified_count = sum(1 for v in aggregated["verification_summary"] if v["has_verification"])

    return {
        "workspace": workspace_path,
        "tasks_found": len(task_files),
        "task_files": [str(f) for f in task_files],
        "rollup_status": aggregated["rollup_status"],
        "status_breakdown": aggregated["statuses"],
        "conflicts_found": len(conflicts),
        "conflicts": [
            {
                "type": c.type,
                "description": c.description,
                "involved": c.involved,
                "resolution": c.resolution,
            }
            for c in conflicts
        ],
        "verification": {
            "tasks_with_evidence": verified_count,
            "tasks_total": len(task_files),
            "coverage": f"{verified_count}/{len(task_files)}",
        },
        "artifacts": {
            "files": aggregated["all_files"],
            "interfaces": aggregated["all_interfaces"],
            "decisions": aggregated["all_decisions"],
        },
        "merge_file": str(merge_path) if merge_path else None,
        "review_file": str(review_path) if review_path else None,
        "ready_to_close": len(conflicts) == 0 and aggregated["rollup_status"] == "SUCCESS",
    }
