# ClawTex — Governed Agent with Genetic Memory
# Built by DeVere Cooley / AN2B LLC · an2b.com
# BB4C — Breath Before Code

"""
ClawTex CLI entry point.

Usage:
  python -m clawtex                  Start the agent (all configured channels)
  python -m clawtex --channel cli    Start in CLI/REPL mode only
  python -m clawtex --channel telegram
  python -m clawtex --channel slack
  python -m clawtex --check          Verify config and governance, then exit
"""

from __future__ import annotations

import argparse
import asyncio
import logging
import os
import sys
from pathlib import Path

from dotenv import load_dotenv

load_dotenv()

logging.basicConfig(
    level=os.environ.get("LOG_LEVEL", "INFO"),
    format="%(asctime)s  %(levelname)-8s  %(name)s  %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger("clawtex")


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        prog="clawtex",
        description="ClawTex — Governed Agent with Genetic Memory · BB4C · AN2B LLC",
    )
    subparsers = parser.add_subparsers(dest="command")

    # clawtex setup
    subparsers.add_parser("setup", help="Interactive first-run configuration wizard")

    # clawtex start
    start = subparsers.add_parser("start", help="Start the agent")
    start.add_argument(
        "--channel",
        choices=["cli", "telegram", "slack", "all"],
        default="all",
    )
    start.add_argument("--name", default=os.environ.get("CLAWTEX_NAME", "ClawTex"))

    # clawtex check
    subparsers.add_parser("check", help="Verify config and governance, then exit")

    # Legacy: no subcommand → start
    parser.add_argument("--channel", choices=["cli", "telegram", "slack", "all"], default="all")
    parser.add_argument("--check", action="store_true")
    parser.add_argument("--name", default=os.environ.get("CLAWTEX_NAME", "ClawTex"))

    return parser.parse_args()


async def run_cli(agent) -> None:
    """Simple REPL for local testing."""
    from clawtex.channels.base import InboundMessage

    print("\n  ClawTex CLI — type 'exit' to quit\n")
    while True:
        try:
            text = input("  You: ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\n  Goodbye. BB4C.")
            break
        if text.lower() in ("exit", "quit", "bye"):
            print("  Goodbye. BB4C.")
            break
        if not text:
            continue

        msg = InboundMessage(
            text=text,
            user_id="cli_user",
            channel="cli",
        )
        reply = await agent.handle_message(msg)
        print(f"\n  Agent: {reply}\n")


async def run_check(agent) -> bool:
    """Verify configuration and governance, return True if all OK."""
    print("\n  ClawTex — Configuration Check\n")
    ok = True

    # Warden policy
    try:
        decision = agent.warden.check("file.delete", {"path": "test"})
        assert decision in ("DENY", "REVIEW"), f"Expected DENY/REVIEW, got {decision}"
        print(f"  ✓ Warden policy loaded — file.delete → {decision}")
    except Exception as exc:
        print(f"  ✗ Warden error: {exc}")
        ok = False

    # MandelDB connectivity (best effort)
    mandeldb_key = os.environ.get("MANDELDB_API_KEY", "")
    if mandeldb_key and not mandeldb_key.endswith("your_key_here"):
        print("  ✓ MANDELDB_API_KEY is set")
    else:
        print("  ! MANDELDB_API_KEY not configured (memory will be unavailable)")

    # LLM provider
    provider = os.environ.get("LLM_PROVIDER", "anthropic")
    if provider == "anthropic" and os.environ.get("ANTHROPIC_API_KEY"):
        print(f"  ✓ LLM provider: {provider}")
    elif provider in ("openai", "openai-compatible") and os.environ.get("OPENAI_API_KEY"):
        print(f"  ✓ LLM provider: {provider}")
    else:
        print(f"  ! LLM API key not set for provider '{provider}'")

    # Skills
    print(f"  ✓ Skills loaded: {len(agent._skills)}")

    # Tools
    from clawtex.tools.registry import registry
    print(f"  ✓ Tools registered: {len(registry.all())}")
    for t in registry.all():
        print(f"     • {t.name} (action_type={t.action_type})")

    print(f"\n  Status: {'✓ OK' if ok else '✗ ERRORS FOUND'}\n")
    return ok


async def main_async() -> None:
    args = parse_args()

    # Import here so dotenv is loaded first
    from clawtex.agent import ClawTexAgent

    agent = ClawTexAgent(name=args.name)
    await agent.start_dream_scheduler()

    if args.check:
        ok = await run_check(agent)
        sys.exit(0 if ok else 1)

    tasks = []

    if args.channel in ("cli", "all"):
        # CLI is always available for local testing
        if args.channel == "cli" or not (
            os.environ.get("TELEGRAM_BOT_TOKEN") or os.environ.get("SLACK_BOT_TOKEN")
        ):
            tasks.append(asyncio.create_task(run_cli(agent)))

    if args.channel in ("telegram", "all") and os.environ.get("TELEGRAM_BOT_TOKEN"):
        from clawtex.channels.telegram import TelegramChannel
        tg = TelegramChannel(handler=agent.handle_message)
        tasks.append(asyncio.create_task(tg.start()))
        logger.info("Telegram channel starting…")

    if args.channel in ("slack", "all") and os.environ.get("SLACK_BOT_TOKEN"):
        from clawtex.channels.slack import SlackChannel
        sl = SlackChannel(handler=agent.handle_message)
        tasks.append(asyncio.create_task(sl.start()))
        logger.info("Slack channel starting…")

    if not tasks:
        logger.info("No channels configured — falling back to CLI mode")
        tasks.append(asyncio.create_task(run_cli(agent)))

    try:
        await asyncio.gather(*tasks)
    except KeyboardInterrupt:
        logger.info("Shutting down… BB4C.")
    finally:
        await agent.close()


def main() -> None:
    print("\n  ClawTex · Governed Agent · Genetic Memory · BB4C · AN2B LLC\n")
    args = parse_args()

    # Handle setup wizard
    if getattr(args, "command", None) == "setup":
        from clawtex.wizard import run_wizard
        run_wizard()
        return

    asyncio.run(main_async())


if __name__ == "__main__":
    main()
