#!/usr/bin/env python3
"""
[DOMAIN NAME] CLI - [Brief description].

This script handles INGESTION and QUERIES. Claude handles SENSEMAKING via the SKILL.md.

Usage:
    python .claude/skills/DOMAIN/DOMAIN.py <command> [options]

Commands:
    # Ingestion
    ingest              Fetch content from URL and store as artifact
    add-entity          Add an entity manually

    # Artifacts (for Claude's sensemaking)
    list-artifacts      List artifacts by analysis status
    show-artifact       Get artifact content for Claude to read

    # Queries
    list-entities       List all entities
    show-entity         Get entity details

    # Updates
    update-status       Update entity status
    add-note            Create a note about any entity
    tag                 Tag an entity
    search-tag          Search by tag

Environment:
    TYPEDB_HOST       TypeDB server host (default: localhost)
    TYPEDB_PORT       TypeDB server port (default: 1729)
    TYPEDB_DATABASE   Database name (default: alhazen_notebook)
    ALHAZEN_CACHE_DIR File cache directory (default: ~/.alhazen/cache)
"""

import argparse
import json
import os
import sys
from pathlib import Path

# Add src to path for imports
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "src"))

# Optional: for URL fetching
try:
    import requests
    from bs4 import BeautifulSoup

    REQUESTS_AVAILABLE = True
except ImportError:
    REQUESTS_AVAILABLE = False

# TypeDB driver
try:
    from typedb.driver import Credentials, DriverOptions, TransactionType, TypeDB

    TYPEDB_AVAILABLE = True
except ImportError:
    TYPEDB_AVAILABLE = False
    print(
        "Warning: typedb-driver not installed. Install with: pip install 'typedb-driver>=3.0.0'",
        file=sys.stderr,
    )

try:
    from skillful_alhazen.utils.skill_helpers import (
        escape_string, generate_id, get_timestamp, check_infrastructure,
    )
except ImportError:
    import uuid
    from datetime import datetime, timezone

    def escape_string(s: str) -> str:
        if s is None:
            return ""
        return s.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n").replace("\r", "")

    def generate_id(prefix: str) -> str:
        return f"{prefix}-{uuid.uuid4().hex[:12]}"

    def get_timestamp() -> str:
        return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")

    def check_infrastructure(*args, **kwargs): pass  # no-op if pkg unavailable

# Cache utilities for large artifacts
try:
    from skillful_alhazen.utils.cache import (
        save_to_cache,
        load_from_cache_text,
        should_cache,
        get_cache_stats,
        format_size,
    )

    CACHE_AVAILABLE = True
except ImportError:
    CACHE_AVAILABLE = False
    # Fallback: define minimal versions if cache module not available
    def should_cache(content):
        return False

    def get_cache_stats():
        return {"error": "Cache module not available"}

    def format_size(size):
        return f"{size} bytes"


# =============================================================================
# CONFIGURATION
# =============================================================================

TYPEDB_HOST = os.getenv("TYPEDB_HOST", "localhost")
TYPEDB_PORT = int(os.getenv("TYPEDB_PORT", "1729"))
TYPEDB_DATABASE = os.getenv("TYPEDB_DATABASE", "alhazen_notebook")
TYPEDB_USERNAME = os.getenv("TYPEDB_USERNAME", "admin")
TYPEDB_PASSWORD = os.getenv("TYPEDB_PASSWORD", "password")

# TODO: Update these constants for your domain
DOMAIN_PREFIX = "domain"  # e.g., "jobhunt", "scilit"
ENTITY_TYPE = f"{DOMAIN_PREFIX}-entity"
ARTIFACT_TYPE = f"{DOMAIN_PREFIX}-artifact"


# =============================================================================
# UTILITIES
# =============================================================================


def get_driver():
    """Get TypeDB driver connection."""
    return TypeDB.driver(
        f"{TYPEDB_HOST}:{TYPEDB_PORT}",
        Credentials(TYPEDB_USERNAME, TYPEDB_PASSWORD),
        DriverOptions(is_tls_enabled=False),
    )


def get_attr(entity: dict, attr_name: str, default=None):
    """Safely extract attribute value from a TypeDB 3.x fetch result dict."""
    return entity.get(attr_name, default)


def fetch_url_content(url: str) -> tuple[str, str]:
    """
    Fetch URL and return (title, text_content).

    Returns basic parsed content - Claude will do the intelligent extraction.
    """
    if not REQUESTS_AVAILABLE:
        return "", ""

    headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"}

    try:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()

        soup = BeautifulSoup(response.text, "html.parser")

        # Remove script and style elements
        for element in soup(["script", "style", "nav", "footer", "header"]):
            element.decompose()

        title = soup.title.string if soup.title else ""

        # Get text content
        text = soup.get_text(separator="\n", strip=True)

        # Clean up whitespace
        lines = [line.strip() for line in text.splitlines() if line.strip()]
        text = "\n".join(lines)

        # Limit content size
        if len(text) > 50000:
            text = text[:50000] + "\n... [truncated]"

        return title, text

    except Exception as e:
        print(f"Error fetching URL: {e}", file=sys.stderr)
        return "", ""


# =============================================================================
# INGESTION COMMANDS
# =============================================================================


def cmd_ingest(args):
    """
    Fetch content from URL and store as artifact.

    This implements the INGESTION phase of the curation pattern:
    - Fetches URL content (raw, unedited)
    - Stores as artifact with provenance
    - Creates placeholder entity
    - Claude does the SENSEMAKING separately
    """
    if not REQUESTS_AVAILABLE:
        print(json.dumps({"success": False, "error": "requests/beautifulsoup4 not installed"}))
        return

    url = args.url
    title, content = fetch_url_content(url)

    if not content:
        print(json.dumps({"success": False, "error": "Could not fetch URL content"}))
        return

    # Generate IDs
    entity_id = generate_id("entity")
    artifact_id = generate_id("artifact")
    timestamp = get_timestamp()

    placeholder_name = title if title else f"Content from {url[:50]}"

    with get_driver() as driver:
        # Create entity placeholder
        with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
            entity_query = f'''insert $e isa {ENTITY_TYPE},
                has id "{entity_id}",
                has name "{escape_string(placeholder_name)}",
                has created-at {timestamp};'''
            tx.query(entity_query).resolve()
            tx.commit()

        # Create artifact with content (inline or cached)
        with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
            # Check if content should be cached externally (>50KB)
            if CACHE_AVAILABLE and should_cache(content):
                # Store in cache
                cache_result = save_to_cache(
                    artifact_id=artifact_id,
                    content=content,
                    mime_type="text/html",
                )
                artifact_query = f'''insert $a isa {ARTIFACT_TYPE},
                    has id "{artifact_id}",
                    has name "Content: {escape_string(placeholder_name)}",
                    has cache-path "{cache_result['cache_path']}",
                    has mime-type "text/html",
                    has file-size {cache_result['file_size']},
                    has content-hash "{cache_result['content_hash']}",
                    has source-uri "{escape_string(url)}",
                    has created-at {timestamp};'''
            else:
                # Store inline in TypeDB
                artifact_query = f'''insert $a isa {ARTIFACT_TYPE},
                    has id "{artifact_id}",
                    has name "Content: {escape_string(placeholder_name)}",
                    has content "{escape_string(content)}",
                    has source-uri "{escape_string(url)}",
                    has created-at {timestamp};'''
            tx.query(artifact_query).resolve()
            tx.commit()

        # Link artifact to entity
        with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
            rep_query = f'''match
                $a isa {ARTIFACT_TYPE}, has id "{artifact_id}";
                $e isa {ENTITY_TYPE}, has id "{entity_id}";
            insert (artifact: $a, referent: $e) isa representation;'''
            tx.query(rep_query).resolve()
            tx.commit()

        # Add tags if specified
        if args.tags:
            for tag_name in args.tags:
                tag_id = generate_id("tag")
                with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
                    tag_check = f'match $t isa tag, has name "{tag_name}"; fetch {{ "id": $t.id }};'
                    existing_tag = list(tx.query(tag_check).resolve())

                if not existing_tag:
                    with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
                        tx.query(
                            f'insert $t isa tag, has id "{tag_id}", has name "{tag_name}";'
                        ).resolve()
                        tx.commit()

                with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
                    tx.query(f'''match
                        $e isa {ENTITY_TYPE}, has id "{entity_id}";
                        $t isa tag, has name "{tag_name}";
                    insert (tagged-entity: $e, tag: $t) isa tagging;''').resolve()
                    tx.commit()

    print(
        json.dumps(
            {
                "success": True,
                "entity_id": entity_id,
                "artifact_id": artifact_id,
                "url": url,
                "content_length": len(content),
                "status": "raw",
                "message": "Content ingested. Artifact stored - ask Claude to 'analyze this' for sensemaking.",
            },
            indent=2,
        )
    )


def cmd_add_entity(args):
    """Add an entity manually."""
    entity_id = args.id or generate_id("entity")
    timestamp = get_timestamp()

    query = f'''insert $e isa {ENTITY_TYPE},
        has id "{entity_id}",
        has name "{escape_string(args.name)}",
        has created-at {timestamp}'''

    if args.description:
        query += f', has description "{escape_string(args.description)}"'

    query += ";"

    with get_driver() as driver:
        with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
            tx.query(query).resolve()
            tx.commit()

    print(json.dumps({"success": True, "entity_id": entity_id, "name": args.name}))


# =============================================================================
# ARTIFACT COMMANDS
# =============================================================================


def cmd_list_artifacts(args):
    """List artifacts, optionally filtered by analysis status."""
    with get_driver() as driver:
        with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
            query = f"""match
                $a isa {ARTIFACT_TYPE};
            fetch {{ "id": $a.id, "name": $a.name, "source-uri": $a.source-uri, "created-at": $a.created-at }};"""
            artifacts = list(tx.query(query).resolve())

            results = []
            for art in artifacts:
                artifact_id = art.get("id")

                # Check for notes (simple heuristic for "analyzed")
                notes_query = f'''match
                    $a isa {ARTIFACT_TYPE}, has id "{artifact_id}";
                    (artifact: $a, referent: $e) isa representation;
                    (note: $n, subject: $e) isa aboutness;
                fetch {{ "id": $n.id }};'''

                try:
                    notes = list(tx.query(notes_query).resolve())
                    has_notes = len(notes) > 0
                except Exception:
                    has_notes = False

                status = "analyzed" if has_notes else "raw"

                if args.status and args.status != "all":
                    if args.status != status:
                        continue

                results.append(
                    {
                        "id": artifact_id,
                        "name": art.get("name"),
                        "source_url": art.get("source-uri"),
                        "created_at": art.get("created-at"),
                        "status": status,
                    }
                )

    print(
        json.dumps(
            {
                "success": True,
                "artifacts": results,
                "count": len(results),
                "filter": args.status or "all",
            },
            indent=2,
        )
    )


def cmd_show_artifact(args):
    """Get artifact content for Claude to read during sensemaking."""
    with get_driver() as driver:
        with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
            # Include cache attributes in fetch
            query = f'''match
                $a isa {ARTIFACT_TYPE}, has id "{args.id}";
            fetch {{ "id": $a.id, "name": $a.name, "content": $a.content, "cache-path": $a.cache-path, "mime-type": $a.mime-type, "file-size": $a.file-size, "source-uri": $a.source-uri, "created-at": $a.created-at }};'''
            result = list(tx.query(query).resolve())

            if not result:
                print(json.dumps({"success": False, "error": "Artifact not found"}))
                return

            # Get linked entity
            entity_query = f'''match
                $a isa {ARTIFACT_TYPE}, has id "{args.id}";
                (artifact: $a, referent: $e) isa representation;
            fetch {{ "id": $e.id, "name": $e.name }};'''
            entity_result = list(tx.query(entity_query).resolve())

    art = result[0]

    # Get content - either from inline content or from cache
    cache_path = art.get("cache-path")
    if cache_path and CACHE_AVAILABLE:
        # Load from cache
        try:
            content = load_from_cache_text(cache_path)
            storage = "cache"
        except FileNotFoundError:
            content = f"[ERROR: Cache file not found: {cache_path}]"
            storage = "cache_missing"
    else:
        # Get inline content
        content = art.get("content")
        storage = "inline"

    output = {
        "success": True,
        "artifact": {
            "id": art.get("id"),
            "name": art.get("name"),
            "source_url": art.get("source-uri"),
            "created_at": art.get("created-at"),
            "content": content,
            "storage": storage,
            "cache_path": cache_path,
            "mime_type": art.get("mime-type"),
            "file_size": art.get("file-size"),
        },
        "entity": None,
    }

    if entity_result:
        ent = entity_result[0]
        output["entity"] = {
            "id": ent.get("id"),
            "name": ent.get("name"),
        }

    print(json.dumps(output, indent=2))


# =============================================================================
# QUERY COMMANDS
# =============================================================================


def cmd_list_entities(args):
    """List all entities."""
    with get_driver() as driver:
        with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
            query = f"""match
                $e isa {ENTITY_TYPE};
            fetch {{ "id": $e.id, "name": $e.name, "created-at": $e.created-at }};"""
            results = list(tx.query(query).resolve())

    entities = []
    for r in results:
        entities.append(
            {
                "id": r.get("id"),
                "name": r.get("name"),
                "created_at": r.get("created-at"),
            }
        )

    print(json.dumps({"success": True, "entities": entities, "count": len(entities)}, indent=2))


def cmd_show_entity(args):
    """Get entity details."""
    with get_driver() as driver:
        with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
            query = f'''match
                $e isa {ENTITY_TYPE}, has id "{args.id}";
            fetch {{ "id": $e.id, "name": $e.name, "description": $e.description, "created-at": $e.created-at }};'''
            result = list(tx.query(query).resolve())

            if not result:
                print(json.dumps({"success": False, "error": "Entity not found"}))
                return

            # Get notes
            notes_query = f'''match
                $e isa {ENTITY_TYPE}, has id "{args.id}";
                (note: $n, subject: $e) isa aboutness;
            fetch {{ "id": $n.id, "name": $n.name, "content": $n.content }};'''
            notes_result = list(tx.query(notes_query).resolve())

            # Get tags
            tags_query = f'''match
                $e isa {ENTITY_TYPE}, has id "{args.id}";
                (tagged-entity: $e, tag: $t) isa tagging;
            fetch {{ "name": $t.name }};'''
            tags_result = list(tx.query(tags_query).resolve())

    output = {
        "success": True,
        "entity": result[0],
        "notes": notes_result,
        "tags": [t.get("name") for t in tags_result],
    }

    print(json.dumps(output, indent=2, default=str))


# =============================================================================
# UPDATE COMMANDS
# =============================================================================


def cmd_add_note(args):
    """Create a note about an entity."""
    note_id = args.id or generate_id("note")
    timestamp = get_timestamp()

    query = f'''insert $n isa note,
        has id "{note_id}",
        has content "{escape_string(args.content)}",
        has created-at {timestamp}'''

    if args.name:
        query += f', has name "{escape_string(args.name)}"'
    if args.confidence:
        query += f", has confidence {args.confidence}"

    query += ";"

    with get_driver() as driver:
        with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
            tx.query(query).resolve()
            tx.commit()

        with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
            about_query = f'''match
                $n isa note, has id "{note_id}";
                $s isa entity, has id "{args.about}";
            insert (note: $n, subject: $s) isa aboutness;'''
            tx.query(about_query).resolve()
            tx.commit()

        if args.tags:
            for tag_name in args.tags:
                tag_id = generate_id("tag")
                with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
                    tag_check = f'match $t isa tag, has name "{tag_name}"; fetch {{ "id": $t.id }};'
                    existing_tag = list(tx.query(tag_check).resolve())

                if not existing_tag:
                    with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
                        tx.query(
                            f'insert $t isa tag, has id "{tag_id}", has name "{tag_name}";'
                        ).resolve()
                        tx.commit()

                with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
                    tx.query(f'''match
                        $n isa note, has id "{note_id}";
                        $t isa tag, has name "{tag_name}";
                    insert (tagged-entity: $n, tag: $t) isa tagging;''').resolve()
                    tx.commit()

    print(json.dumps({"success": True, "note_id": note_id, "about": args.about}))


def cmd_tag(args):
    """Tag an entity."""
    with get_driver() as driver:
        tag_id = generate_id("tag")
        with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
            tag_check = f'match $t isa tag, has name "{args.tag}"; fetch {{ "id": $t.id }};'
            existing_tag = list(tx.query(tag_check).resolve())

        if not existing_tag:
            with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
                tx.query(f'insert $t isa tag, has id "{tag_id}", has name "{args.tag}";').resolve()
                tx.commit()

        with driver.transaction(TYPEDB_DATABASE, TransactionType.WRITE) as tx:
            tx.query(f'''match
                $e isa entity, has id "{args.entity}";
                $t isa tag, has name "{args.tag}";
            insert (tagged-entity: $e, tag: $t) isa tagging;''').resolve()
            tx.commit()

    print(json.dumps({"success": True, "entity": args.entity, "tag": args.tag}))


def cmd_search_tag(args):
    """Search entities by tag."""
    with get_driver() as driver:
        with driver.transaction(TYPEDB_DATABASE, TransactionType.READ) as tx:
            query = f'''match
                $t isa tag, has name "{args.tag}";
                (tagged-entity: $e, tag: $t) isa tagging;
            fetch {{ "id": $e.id, "name": $e.name }};'''
            results = list(tx.query(query).resolve())

    print(
        json.dumps(
            {
                "success": True,
                "tag": args.tag,
                "entities": results,
                "count": len(results),
            },
            indent=2,
            default=str,
        )
    )


# =============================================================================
# MAIN
# =============================================================================


def main():
    # Infrastructure check — fast-fails with helpful message if TypeDB/dashboard missing
    check_infrastructure(
        skill_name="DOMAIN",                      # replace with actual skill name
        schema_check_type="DOMAIN-main-entity",   # replace: first entity in schema.tql
        has_dashboard=False,                      # set True if skill has dashboard/
        zip_name="domain-v1.0.zip",               # replace: from skill.yaml bundle.zip_name
    )

    parser = argparse.ArgumentParser(
        description="[DOMAIN] CLI - [Brief description]"
    )
    subparsers = parser.add_subparsers(dest="command", help="Command to run")

    # ingest
    p = subparsers.add_parser("ingest", help="Fetch content from URL and store as artifact")
    p.add_argument("--url", required=True, help="Source URL")
    p.add_argument("--tags", nargs="+", help="Tags to apply")

    # add-entity
    p = subparsers.add_parser("add-entity", help="Add an entity manually")
    p.add_argument("--name", required=True, help="Entity name")
    p.add_argument("--description", help="Description")
    p.add_argument("--id", help="Specific ID")

    # list-artifacts
    p = subparsers.add_parser("list-artifacts", help="List artifacts by status")
    p.add_argument(
        "--status",
        choices=["raw", "analyzed", "all"],
        help="Filter: raw, analyzed, or all",
    )

    # show-artifact
    p = subparsers.add_parser("show-artifact", help="Get artifact content")
    p.add_argument("--id", required=True, help="Artifact ID")

    # list-entities
    subparsers.add_parser("list-entities", help="List all entities")

    # show-entity
    p = subparsers.add_parser("show-entity", help="Get entity details")
    p.add_argument("--id", required=True, help="Entity ID")

    # add-note
    p = subparsers.add_parser("add-note", help="Create a note")
    p.add_argument("--about", required=True, help="Entity ID this note is about")
    p.add_argument("--content", required=True, help="Note content")
    p.add_argument("--name", help="Note title")
    p.add_argument("--confidence", type=float, help="Confidence score (0.0-1.0)")
    p.add_argument("--tags", nargs="+", help="Tags to apply")
    p.add_argument("--id", help="Specific ID")

    # tag
    p = subparsers.add_parser("tag", help="Tag an entity")
    p.add_argument("--entity", required=True, help="Entity ID")
    p.add_argument("--tag", required=True, help="Tag name")

    # search-tag
    p = subparsers.add_parser("search-tag", help="Search by tag")
    p.add_argument("--tag", required=True, help="Tag to search for")

    args = parser.parse_args()

    if not TYPEDB_AVAILABLE:
        print(json.dumps({"success": False, "error": "typedb-driver not installed"}))
        sys.exit(1)

    if not args.command:
        parser.print_help()
        sys.exit(1)

    commands = {
        "ingest": cmd_ingest,
        "add-entity": cmd_add_entity,
        "list-artifacts": cmd_list_artifacts,
        "show-artifact": cmd_show_artifact,
        "list-entities": cmd_list_entities,
        "show-entity": cmd_show_entity,
        "add-note": cmd_add_note,
        "tag": cmd_tag,
        "search-tag": cmd_search_tag,
    }

    try:
        commands[args.command](args)
    except Exception as e:
        print(json.dumps({"success": False, "error": str(e)}))
        import traceback

        traceback.print_exc(file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()
