"""MCP server for the review system (stdio + background HTTP API)."""

from __future__ import annotations

import json
import os
import threading
from datetime import datetime, timezone
from typing import Optional

from mcp.server.fastmcp import FastMCP

from . import db
from .file_finder import find_source_file

PROJECT_ROOT = os.environ.get("PROJECT_ROOT", "")

mcp = FastMCP("review-system")


def _format_element_context(metadata_str: str | None) -> str:
    """Format annotation metadata into a human-readable element context line."""
    if not metadata_str:
        return ""
    try:
        meta = json.loads(metadata_str) if isinstance(metadata_str, str) else metadata_str
    except (json.JSONDecodeError, TypeError):
        return ""
    parts = []
    if meta.get("element"):
        parts.append(f"Element: {meta['element']}")
    if meta.get("selector"):
        parts.append(f"Selector: {meta['selector']}")
    if meta.get("selectedText"):
        parts.append(f'Selected: "{meta["selectedText"]}"')
    return " | ".join(parts)


@mcp.tool()
async def get_review_summary() -> str:
    """Get a summary of all pages with open/resolved review counts."""
    await db.init_db()
    rows = await db.get_summary()
    if not rows:
        return "No reviews found."

    lines = ["Page | Open | Resolved | Total", "--- | --- | --- | ---"]
    for r in rows:
        lines.append(f"{r['page_id']} | {r['open']} | {r['resolved']} | {r['total']}")
    return "\n".join(lines)


@mcp.tool()
async def get_reviews(page_id: Optional[str] = None) -> str:
    """Get review comments, optionally filtered by page_id."""
    await db.init_db()
    rows = await db.get_reviews(page_id)
    if not rows:
        return f"No reviews found{' for ' + page_id if page_id else ''}."

    lines = []
    for r in rows:
        status = "OPEN" if r["status"] == "open" else "RESOLVED"
        tag = r.get("tag", "general") or "general"
        parent = f" (reply to #{r['parent_id']})" if r.get("parent_id") else ""
        line = f"[#{r['id']}] [{status}] [{tag}] {r['page_id']} - {r['author']}: {r['text']}{parent}"
        ctx = _format_element_context(r.get("metadata"))
        if ctx:
            line += f"\n    [{ctx}]"
        lines.append(line)
    return "\n".join(lines)


@mcp.tool()
async def add_review(
    page_id: str,
    author: str,
    text: str,
    metadata: Optional[str] = None,
    tag: str = "general",
    parent_id: Optional[int] = None,
) -> str:
    """Add a new review comment to a page. Optional metadata is a JSON string with element annotation context. Tag can be: bug, suggestion, question, general. Set parent_id to reply to an existing review."""
    await db.init_db()
    review = await db.insert_review(page_id, author, text, metadata, tag=tag, parent_id=parent_id)
    return f"Created review #{review['id']} on {page_id} by {author} [{tag}]."


@mcp.tool()
async def resolve_review(review_id: int, resolved_by: str = "agent") -> str:
    """Mark a review as resolved."""
    await db.init_db()
    now = datetime.now(timezone.utc).isoformat()
    result = await db.update_review(
        review_id, status="resolved", resolved_at=now, resolved_by=resolved_by
    )
    if result is None:
        return f"Review #{review_id} not found."
    return f"Review #{review_id} resolved by {resolved_by}."


@mcp.tool()
async def reopen_review(review_id: int) -> str:
    """Reopen a previously resolved review."""
    await db.init_db()
    result = await db.update_review(
        review_id, status="open", resolved_at=None, resolved_by=None
    )
    if result is None:
        return f"Review #{review_id} not found."
    return f"Review #{review_id} reopened."


@mcp.tool()
async def batch_resolve(page_id: str, resolved_by: str = "agent") -> str:
    """Resolve all open reviews on a page."""
    await db.init_db()
    count = await db.batch_resolve(page_id, resolved_by)
    return f"Resolved {count} review(s) on {page_id}."


@mcp.tool()
async def get_pending_work() -> str:
    """Get all open reviews grouped by page. Ready-to-work list for agents."""
    await db.init_db()
    pages = await db.get_open_reviews_by_page()
    if not pages:
        return "No pending reviews. All clear!"

    lines = []
    for p in pages:
        lines.append(f"\n## {p['page_id']} ({len(p['reviews'])} open)")
        for r in p["reviews"]:
            tag = r.get("tag", "general") or "general"
            line = f"  - #{r['id']} [{tag}] ({r['author']}): {r['text']}"
            ctx = _format_element_context(r.get("metadata"))
            if ctx:
                line += f"\n    [{ctx}]"
            lines.append(line)
    return "\n".join(lines)


@mcp.tool()
async def find_source_file_tool(page_id: str) -> str:
    """Find source files in PROJECT_ROOT that match a page_id."""
    if not PROJECT_ROOT:
        return "PROJECT_ROOT environment variable is not set."

    matches = find_source_file(page_id, PROJECT_ROOT)
    if not matches:
        return f"No source files found for page_id '{page_id}' in {PROJECT_ROOT}."

    lines = [f"Found {len(matches)} file(s) for '{page_id}':"]
    for m in matches:
        lines.append(f"  - {m}")
    return "\n".join(lines)


@mcp.tool()
async def get_setup_guide() -> str:
    """Get the full setup guide for the review system (MCP server + REST API + Angular component)."""
    port = os.environ.get("REVIEW_PORT", "3200")
    return f"""# ui-ticket-mcp Setup Guide

MCP server (stdio) + REST API (HTTP on port {port}) start together automatically.

## 1. Add to `.mcp.json`

```json
{{
  "mcpServers": {{
    "review-system": {{
      "command": "uvx",
      "args": ["ui-ticket-mcp"],
      "env": {{
        "PROJECT_ROOT": "/path/to/your/project"
      }}
    }}
  }}
}}
```

Restart the agent. MCP connects via stdio, REST API starts in background on http://localhost:{port}.

Port configurable via `REVIEW_PORT` env var.

## 2. Angular component (optional)

```bash
npm install ui-ticket-review-panel
```

```typescript
import {{ ReviewPanelComponent, REVIEW_API_BASE_URL }} from 'ui-ticket-review-panel';

@Component({{
  imports: [ReviewPanelComponent],
  providers: [{{ provide: REVIEW_API_BASE_URL, useValue: 'http://localhost:{port}/api' }}],
  template: `<review-panel />`
}})
export class AppComponent {{}}
```

## Database

Reviews are stored in `{{PROJECT_ROOT}}/.reviews/reviews.db` (auto-created, committable to git).
Override with `REVIEW_DB_PATH` env var.

## Agent workflow

1. `get_pending_work()` - see what needs attention
2. `find_source_file_tool("page-id")` - locate source files
3. (read/edit the code)
4. `resolve_review(id)` or `batch_resolve("page-id")` - mark as done
"""


@mcp.tool()
async def get_annotated_reviews(page_id: Optional[str] = None) -> str:
    """Get only reviews that have element annotation metadata. Shows full element context for targeted fixes."""
    await db.init_db()
    rows = await db.get_reviews(page_id)
    annotated = [r for r in rows if r.get("metadata")]
    if not annotated:
        return f"No annotated reviews found{' for ' + page_id if page_id else ''}."

    lines = []
    for r in annotated:
        status = "OPEN" if r["status"] == "open" else "RESOLVED"
        lines.append(f"[#{r['id']}] [{status}] {r['page_id']} - {r['author']}: {r['text']}")
        try:
            meta = json.loads(r["metadata"]) if isinstance(r["metadata"], str) else r["metadata"]
            if meta.get("element"):
                lines.append(f"    Element: {meta['element']}")
            if meta.get("selector"):
                lines.append(f"    Selector: {meta['selector']}")
            if meta.get("fullPath"):
                lines.append(f"    Full path: {meta['fullPath']}")
            if meta.get("selectedText"):
                lines.append(f'    Selected text: "{meta["selectedText"]}"')
            if meta.get("accessibility"):
                lines.append(f"    Accessibility: {meta['accessibility']}")
            if meta.get("computedStyles"):
                lines.append(f"    Styles: {meta['computedStyles']}")
        except (json.JSONDecodeError, TypeError):
            pass
    return "\n".join(lines)


# --------------- Background API server ---------------


def _start_api_server():
    """Start the FastAPI REST server in a background thread."""
    import uvicorn
    from .api import app

    port = int(os.environ.get("REVIEW_PORT", "3200"))
    uvicorn.run(app, host="0.0.0.0", port=port, log_level="warning")


# --------------- Main ---------------


def main():
    api_thread = threading.Thread(target=_start_api_server, daemon=True)
    api_thread.start()
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()
