#!/usr/bin/env python3
"""ORION-AI CLI client for remote event ingestion."""

from __future__ import annotations

import argparse
import sys
from pathlib import Path
from typing import Any
from urllib.parse import quote_plus

try:
    import requests
    from requests.exceptions import ConnectionError as RequestsConnectionError
    from requests.exceptions import RequestException, Timeout
except ModuleNotFoundError:
    requests = None
    RequestsConnectionError = Exception
    RequestException = Exception
    Timeout = Exception

REQUEST_TIMEOUT_SECONDS = 15


def build_parser() -> argparse.ArgumentParser:
    """Build and return CLI argument parser."""
    parser = argparse.ArgumentParser(description="ORION-AI remote ingestion client")
    subparsers = parser.add_subparsers(dest="command", required=True)

    send_parser = subparsers.add_parser("send", help="Send one event to ORION-AI backend")
    send_parser.add_argument("--server", default="http://127.0.0.1:8000", help="Backend URL")
    send_parser.add_argument("--engagement-id", type=int, required=True, help="Engagement ID")
    send_parser.add_argument("--phase", required=True, help="Event phase")
    send_parser.add_argument("--source", required=True, help="Event source")
    send_parser.add_argument("--title", required=True, help="Event title")
    send_parser.add_argument(
        "--severity",
        choices=("low", "med", "high"),
        required=True,
        help="Event severity",
    )
    send_parser.add_argument(
        "--tags",
        default="",
        help="Comma-separated tags (example: web,auth,critical)",
    )
    send_parser.add_argument("--file", help="Path to file containing event content")
    send_parser.add_argument("--content", help="Raw event content text")

    vault_register_parser = subparsers.add_parser("vault-register", help="Register a local vault path")
    vault_register_parser.add_argument("--server", default="http://127.0.0.1:8000", help="Backend URL")
    vault_register_parser.add_argument("--path", required=True, help="Path to register")

    vault_index_parser = subparsers.add_parser("vault-index", help="Run vault indexing")
    vault_index_parser.add_argument("--server", default="http://127.0.0.1:8000", help="Backend URL")
    vault_index_parser.add_argument("--path-id", type=int, help="Optional vault path id")

    vault_search_parser = subparsers.add_parser("vault-search", help="Search vault chunks")
    vault_search_parser.add_argument("--server", default="http://127.0.0.1:8000", help="Backend URL")
    vault_search_parser.add_argument("--q", required=True, help="Query text")
    vault_search_parser.add_argument("--limit", type=int, default=10, help="Max results")

    return parser


def _parse_tags(raw_tags: str) -> list[str]:
    """Convert comma-separated tags to a clean list."""
    if not raw_tags.strip():
        return []
    return [tag.strip() for tag in raw_tags.split(",") if tag.strip()]


def _load_content(file_path: str | None, inline_content: str | None) -> str:
    """Load event content from file or inline text."""
    if file_path:
        path = Path(file_path)
        if not path.is_file():
            raise ValueError(f"file not found: {file_path}")
        content = path.read_text(encoding="utf-8").strip()
        if not content:
            raise ValueError("file content is empty")
        return content

    if inline_content and inline_content.strip():
        return inline_content.strip()

    raise ValueError("you must provide --file or --content")


def _extract_error_detail(response: Any) -> str:
    """Extract a readable error message from HTTP response."""
    try:
        payload = response.json()
    except ValueError:
        text = response.text.strip()
        return text or "unknown error"

    if isinstance(payload, dict):
        detail = payload.get("detail")
        if isinstance(detail, str):
            return detail
        if isinstance(detail, list):
            return ", ".join(str(item) for item in detail)

    return "unknown error"


def send_event(args: argparse.Namespace) -> int:
    """Send event payload to ORION-AI backend."""
    if requests is None:
        print(
            "Error: requests is not installed. Run: pip install -r requirements.txt",
            file=sys.stderr,
        )
        return 1

    try:
        content = _load_content(args.file, args.content)
    except ValueError as exc:
        print(f"Error: {exc}", file=sys.stderr)
        return 1

    payload: dict[str, Any] = {
        "engagement_id": args.engagement_id,
        "phase": args.phase,
        "source": args.source,
        "title": args.title,
        "severity": args.severity,
        "tags": _parse_tags(args.tags),
        "content": content,
    }

    endpoint = f"{args.server.rstrip('/')}/events"
    try:
        response = requests.post(
            endpoint,
            json=payload,
            timeout=REQUEST_TIMEOUT_SECONDS,
        )
    except RequestsConnectionError:
        print(f"Error: could not connect to server {args.server}", file=sys.stderr)
        return 1
    except Timeout:
        print(f"Error: request timed out after {REQUEST_TIMEOUT_SECONDS}s", file=sys.stderr)
        return 1
    except RequestException as exc:
        print(f"Error: request failed ({exc})", file=sys.stderr)
        return 1

    if response.ok:
        try:
            response_payload = response.json()
        except ValueError:
            response_payload = {}
        event_id = response_payload.get("id", "unknown")
        print(f"Event sent successfully (id: {event_id})")
        return 0

    detail = _extract_error_detail(response)
    print(f"Error {response.status_code}: {detail}", file=sys.stderr)
    return 1


def _post_json(server: str, endpoint: str, payload: dict[str, Any]) -> tuple[int, Any]:
    """POST helper for vault commands."""
    response = requests.post(
        f"{server.rstrip('/')}{endpoint}",
        json=payload,
        timeout=REQUEST_TIMEOUT_SECONDS,
    )
    try:
        body = response.json()
    except ValueError:
        body = response.text.strip()
    return response.status_code, body


def _get_json(server: str, endpoint: str) -> tuple[int, Any]:
    """GET helper for vault commands."""
    response = requests.get(
        f"{server.rstrip('/')}{endpoint}",
        timeout=REQUEST_TIMEOUT_SECONDS,
    )
    try:
        body = response.json()
    except ValueError:
        body = response.text.strip()
    return response.status_code, body


def vault_register(args: argparse.Namespace) -> int:
    """Register one vault path via API."""
    if requests is None:
        print("Error: requests is not installed. Run: pip install -r requirements.txt", file=sys.stderr)
        return 1

    try:
        status_code, body = _post_json(args.server, "/vault/register", {"path": args.path})
    except RequestException as exc:
        print(f"Error: request failed ({exc})", file=sys.stderr)
        return 1

    if 200 <= status_code < 300:
        print(body)
        return 0
    detail = body.get("detail") if isinstance(body, dict) else body
    print(f"Error {status_code}: {detail}", file=sys.stderr)
    return 1


def vault_index(args: argparse.Namespace) -> int:
    """Trigger vault indexing via API."""
    if requests is None:
        print("Error: requests is not installed. Run: pip install -r requirements.txt", file=sys.stderr)
        return 1

    payload: dict[str, Any] = {}
    if args.path_id is not None:
        payload["path_id"] = args.path_id

    try:
        status_code, body = _post_json(args.server, "/vault/index", payload)
    except RequestException as exc:
        print(f"Error: request failed ({exc})", file=sys.stderr)
        return 1

    if 200 <= status_code < 300:
        print(body)
        return 0
    detail = body.get("detail") if isinstance(body, dict) else body
    print(f"Error {status_code}: {detail}", file=sys.stderr)
    return 1


def vault_search(args: argparse.Namespace) -> int:
    """Search vault snippets via API."""
    if requests is None:
        print("Error: requests is not installed. Run: pip install -r requirements.txt", file=sys.stderr)
        return 1

    try:
        status_code, body = _get_json(
            args.server,
            f"/vault/search?q={quote_plus(args.q)}&limit={args.limit}",
        )
    except RequestException as exc:
        print(f"Error: request failed ({exc})", file=sys.stderr)
        return 1

    if 200 <= status_code < 300:
        print(body)
        return 0
    detail = body.get("detail") if isinstance(body, dict) else body
    print(f"Error {status_code}: {detail}", file=sys.stderr)
    return 1


def main() -> int:
    """CLI entrypoint."""
    parser = build_parser()
    args = parser.parse_args()

    if args.command == "send":
        return send_event(args)
    if args.command == "vault-register":
        return vault_register(args)
    if args.command == "vault-index":
        return vault_index(args)
    if args.command == "vault-search":
        return vault_search(args)

    parser.print_help()
    return 1


if __name__ == "__main__":
    raise SystemExit(main())
