"""Relationship profile API — read, update, and view activity context."""

from __future__ import annotations

import re

from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel

router = APIRouter(prefix="/relationship", tags=["relationship"])


class RelationshipSection(BaseModel):
    name: str
    content: str
    item_count: int


class RelationshipResponse(BaseModel):
    content: str
    sections: list[RelationshipSection]
    metadata: dict
    activity_context: str
    last_evolved: str | None


class RelationshipUpdateRequest(BaseModel):
    content: str


class SectionInsightRequest(BaseModel):
    section: str
    insight: str
    action: str = "add"  # "add" or "remove"


def _parse_sections(content: str) -> list[RelationshipSection]:
    """Parse RELATIONSHIP.md into sections."""
    sections: list[RelationshipSection] = []
    current_name = ""
    current_lines: list[str] = []

    for line in content.split("\n"):
        if line.strip().startswith("## "):
            if current_name:
                body = "\n".join(current_lines).strip()
                # Count non-empty, non-hint lines as items
                items = [
                    ln for ln in current_lines
                    if ln.strip()
                    and not (ln.strip().startswith("*") and ln.strip().endswith("*"))
                ]
                sections.append(RelationshipSection(
                    name=current_name, content=body, item_count=len(items),
                ))
            current_name = line.strip().lstrip("# ").strip()
            current_lines = []
        elif current_name:
            current_lines.append(line)

    # Last section
    if current_name:
        body = "\n".join(current_lines).strip()
        items = [
            ln for ln in current_lines
            if ln.strip()
            and not (ln.strip().startswith("*") and ln.strip().endswith("*"))
        ]
        sections.append(RelationshipSection(
            name=current_name, content=body, item_count=len(items),
        ))

    return sections


@router.get("")
async def get_relationship(request: Request) -> RelationshipResponse:
    """Get RELATIONSHIP.md with parsed sections and live activity context."""
    vault = request.app.state.vault
    rel_path = "system/identity/RELATIONSHIP.md"

    try:
        doc = vault.read(rel_path)
    except FileNotFoundError as exc:
        raise HTTPException(status_code=404, detail="RELATIONSHIP.md not found") from exc

    content = doc.content or ""
    sections = _parse_sections(content)
    metadata = doc.metadata or {}

    # Live activity context
    activity_context = ""
    activity = getattr(request.app.state, "activity_logger", None)
    if activity:
        try:
            activity_context = activity.get_relationship_context()
        except Exception:
            pass

    # Try to find last evolution date from the content
    last_evolved = None
    date_matches = re.findall(r"\[(\d{4}-\d{2}-\d{2})\]", content)
    if date_matches:
        last_evolved = max(date_matches)

    return RelationshipResponse(
        content=content,
        sections=sections,
        metadata=metadata,
        activity_context=activity_context,
        last_evolved=last_evolved,
    )


@router.put("")
async def update_relationship(request: Request, body: RelationshipUpdateRequest) -> RelationshipResponse:
    """Update the full RELATIONSHIP.md content."""
    writer = request.app.state.writer
    rel_path = "system/identity/RELATIONSHIP.md"

    writer.write(rel_path, body.content, trust_reason="user_edit_relationship")

    # Log activity
    activity = getattr(request.app.state, "activity_logger", None)
    if activity:
        try:
            activity.log(
                category="user_override",
                action="relationship_edited",
                summary="User edited RELATIONSHIP.md via control panel",
                details={"lines": len(body.content.split("\n"))},
                importance="medium",
            )
        except Exception:
            pass

    # Read back
    vault = request.app.state.vault
    doc = vault.read(rel_path)
    content = doc.content or ""
    sections = _parse_sections(content)

    activity_context = ""
    if activity:
        try:
            activity_context = activity.get_relationship_context()
        except Exception:
            pass

    last_evolved = None
    date_matches = re.findall(r"\[(\d{4}-\d{2}-\d{2})\]", content)
    if date_matches:
        last_evolved = max(date_matches)

    return RelationshipResponse(
        content=content,
        sections=sections,
        metadata=doc.metadata or {},
        activity_context=activity_context,
        last_evolved=last_evolved,
    )


@router.post("/insight")
async def add_relationship_insight(request: Request, body: SectionInsightRequest) -> dict:
    """Add or remove a single insight from a specific section."""
    vault = request.app.state.vault
    writer = request.app.state.writer
    rel_path = "system/identity/RELATIONSHIP.md"

    try:
        doc = vault.read(rel_path)
        content = doc.content or ""
    except FileNotFoundError as exc:
        raise HTTPException(status_code=404, detail="RELATIONSHIP.md not found") from exc

    heading = f"## {body.section}"
    if heading not in content:
        raise HTTPException(status_code=400, detail=f"Section '{body.section}' not found")

    lines = content.split("\n")
    result_lines: list[str] = []
    in_section = False
    inserted = False

    for line in lines:
        if line.strip().startswith("## "):
            if in_section and body.action == "add" and not inserted:
                result_lines.append(f"- {body.insight}")
                result_lines.append("")
                inserted = True
            in_section = line.strip() == heading
        if in_section and body.action == "remove" and body.insight.lower() in line.lower():
            continue
        result_lines.append(line)

    if in_section and body.action == "add" and not inserted:
        # Remove placeholder hint
        while result_lines and result_lines[-1].strip() == "":
            result_lines.pop()
        if result_lines and result_lines[-1].strip().startswith("*") and result_lines[-1].strip().endswith("*"):
            result_lines.pop()
        result_lines.append(f"- {body.insight}")
        result_lines.append("")

    new_content = "\n".join(result_lines)
    writer.write(rel_path, new_content, trust_reason="user_relationship_insight")

    # Log activity
    activity = getattr(request.app.state, "activity_logger", None)
    if activity:
        try:
            verb = "added to" if body.action == "add" else "removed from"
            activity.log(
                category="user_override",
                action="relationship_insight_edited",
                summary=f"User {verb} {body.section} in RELATIONSHIP.md",
                details={"section": body.section, "action": body.action},
                importance="medium",
            )
        except Exception:
            pass

    return {"status": "ok", "section": body.section, "action": body.action}


# ── Pending evolution approval ────────────────────────────────


class PendingEvolution(BaseModel):
    content: str
    date: str | None
    status: str


@router.get("/pending")
async def get_pending_evolution(request: Request) -> PendingEvolution | dict:
    """Get the pending relationship evolution, if any."""
    vault = request.app.state.vault
    pending_path = "memory/pending/relationship-evolution.md"
    try:
        doc = vault.read(pending_path)
    except (FileNotFoundError, Exception):
        return {"content": "", "date": None, "status": "none"}

    content = doc.content or ""
    raw_date = (doc.metadata or {}).get("date")
    # Frontmatter YAML parses `date: 2026-04-19` as datetime.date; coerce to str.
    date = raw_date.isoformat() if hasattr(raw_date, "isoformat") else (raw_date if isinstance(raw_date, str) else None)
    status = (doc.metadata or {}).get("status", "pending")
    return PendingEvolution(content=content, date=date, status=status)


@router.post("/pending/approve")
async def approve_pending_evolution(request: Request) -> dict:
    """Approve the pending evolution — apply it to RELATIONSHIP.md.

    Accepts an optional JSON body with ``content`` to use the user's
    edited version instead of the raw proposal.
    """
    vault = request.app.state.vault
    writer = request.app.state.writer
    pending_path = "memory/pending/relationship-evolution.md"

    try:
        doc = vault.read(pending_path)
    except (FileNotFoundError, Exception) as exc:
        raise HTTPException(status_code=404, detail="No pending evolution") from exc

    # Capture correlation_id from the pending file for evolution feedback.
    _rel_corr_id = str((doc.metadata or {}).get("correlation_id", ""))

    # Use edited content if provided, otherwise use the proposal as-is
    try:
        body = await request.json()
    except Exception:
        body = {}
    edited = body.get("content") if isinstance(body, dict) else None

    proposed = edited if edited is not None else (doc.content or "")
    if not proposed.strip():
        raise HTTPException(status_code=400, detail="Pending evolution is empty")

    # Strip any leftover frontmatter from the proposed content — the
    # actual RELATIONSHIP.md already has its own frontmatter.
    # The proposed content is the full body the LLM returned.
    writer.write(
        "system/identity/RELATIONSHIP.md",
        proposed,
        trust_reason="relationship_evolution_approved",
    )

    # Remove the pending file
    import os
    pending_physical = vault._resolve_path(pending_path) if hasattr(vault, "_resolve_path") else None
    if pending_physical and os.path.exists(pending_physical):
        os.unlink(pending_physical)
    else:
        # Fallback: overwrite with empty
        try:
            writer.write(pending_path, "", trust_reason="relationship_pending_cleared")
        except Exception:
            pass

    # Log
    activity = getattr(request.app.state, "activity_logger", None)
    if activity:
        try:
            activity.log(
                category="user_override",
                action="relationship_evolution_approved",
                summary="User approved weekly relationship evolution",
                details={"lines": len(proposed.split("\n"))},
                importance="high",
            )
        except Exception:
            pass

    review_history = getattr(request.app.state, "review_history", None)
    if review_history:
        await review_history.record("relationship", "relationship-evolution", "approved",
                                    details={"lines": len(proposed.split("\n"))})

    # Evolution feedback — positive signal on the relationship-evolution run.
    evolution = getattr(request.app.state, "evolution", None)
    if evolution is not None and _rel_corr_id:
        await evolution.record_feedback_by_correlation(_rel_corr_id, 1.0)

    return {"status": "approved", "lines": len(proposed.split("\n"))}


@router.post("/pending/reject")
async def reject_pending_evolution(request: Request) -> dict:
    """Reject the pending evolution — discard it."""
    vault = request.app.state.vault
    writer = request.app.state.writer
    pending_path = "memory/pending/relationship-evolution.md"

    try:
        _reject_doc = vault.read(pending_path)
    except (FileNotFoundError, Exception) as exc:
        raise HTTPException(status_code=404, detail="No pending evolution") from exc

    # Capture correlation_id BEFORE deleting the pending file.
    _reject_corr_id = str((_reject_doc.metadata or {}).get("correlation_id", ""))

    try:
        body = await request.json()
    except Exception:
        body = {}
    reason = body.get("reason", "") if isinstance(body, dict) else ""

    # Remove the pending file
    import os
    pending_physical = vault._resolve_path(pending_path) if hasattr(vault, "_resolve_path") else None
    if pending_physical and os.path.exists(pending_physical):
        os.unlink(pending_physical)
    else:
        try:
            writer.write(pending_path, "", trust_reason="relationship_pending_rejected")
        except Exception:
            pass

    activity = getattr(request.app.state, "activity_logger", None)
    if activity:
        try:
            activity.log(
                category="user_override",
                action="relationship_evolution_rejected",
                summary="User rejected weekly relationship evolution" + (f" — {reason}" if reason else ""),
                details={"reason": reason} if reason else {},
                importance="medium",
            )
        except Exception:
            pass

    # Evolution feedback — rejection signal (score 0.0).
    evolution = getattr(request.app.state, "evolution", None)
    if evolution is not None and _reject_corr_id:
        await evolution.record_feedback_by_correlation(_reject_corr_id, 0.0)

    review_history = getattr(request.app.state, "review_history", None)
    if review_history:
        await review_history.record("relationship", "relationship-evolution", "rejected",
                                    reason=reason)

    return {"status": "rejected"}
