#!/usr/bin/env python3
"""
PromptCanvas CLI

Pull production prompts from PromptCanvas and store them locally in your project.

Usage:
    promptcanvas init                    # Initialize config file
    promptcanvas pull <slug>             # Pull a specific prompt
    promptcanvas pull --all              # Pull all production prompts
    promptcanvas list                    # List available prompts
"""

import argparse
import json
import os
import sys
from pathlib import Path
from typing import Any, Dict, Optional

from .client import PromptCanvas
from .models import Prompt, PromptMeta


# ANSI colors
class Colors:
    RESET = "\033[0m"
    GREEN = "\033[32m"
    RED = "\033[31m"
    YELLOW = "\033[33m"
    BLUE = "\033[34m"
    CYAN = "\033[36m"
    DIM = "\033[2m"
    BOLD = "\033[1m"


CONFIG_FILE = "promptcanvas.json"

DEFAULT_CONFIG = {
    "outputDir": "prompts",
    "format": "json",
    "includeMetadata": True,
}


def log_success(message: str) -> None:
    print(f"{Colors.GREEN}✓{Colors.RESET} {message}")


def log_error(message: str) -> None:
    print(f"{Colors.RED}✗{Colors.RESET} {message}", file=sys.stderr)


def log_info(message: str) -> None:
    print(f"{Colors.BLUE}ℹ{Colors.RESET} {message}")


def log_warning(message: str) -> None:
    print(f"{Colors.YELLOW}⚠{Colors.RESET} {message}")


def find_config_file() -> Optional[Path]:
    """Find config file in current or parent directories."""
    current = Path.cwd()
    while True:
        config_path = current / CONFIG_FILE
        if config_path.exists():
            return config_path
        parent = current.parent
        if parent == current:
            break
        current = parent
    return None


def load_config() -> Dict[str, Any]:
    """Load configuration from file."""
    config_path = find_config_file()
    if config_path:
        try:
            with open(config_path, "r") as f:
                config = json.load(f)
                return {**DEFAULT_CONFIG, **config}
        except Exception:
            log_warning(f"Failed to parse {CONFIG_FILE}, using defaults")
    return DEFAULT_CONFIG.copy()


def get_api_key(config: Dict[str, Any]) -> str:
    """Get API key from environment or config."""
    env_key = os.environ.get("PROMPTCANVAS_API_KEY")
    if env_key:
        return env_key
    if config.get("apiKey"):
        return config["apiKey"]
    
    log_error(
        "API key not found. Set PROMPTCANVAS_API_KEY environment variable "
        "or add apiKey to promptcanvas.json"
    )
    sys.exit(1)


def ensure_output_dir(output_dir: str) -> Path:
    """Ensure output directory exists."""
    path = Path.cwd() / output_dir
    if not path.exists():
        path.mkdir(parents=True)
        log_info(f"Created directory: {output_dir}")
    return path


def save_prompt(prompt: Prompt, config: Dict[str, Any]) -> Path:
    """Save a prompt to a local file."""
    output_dir = ensure_output_dir(config["outputDir"])
    
    fmt = config.get("format", "json")
    filename = f"{prompt.slug}.{fmt}"
    filepath = output_dir / filename

    if fmt == "json":
        if config.get("includeMetadata", True):
            data = {
                "slug": prompt.slug,
                "name": prompt.name,
                "content": prompt.content,
                "version": prompt.version,
                "variables": prompt.variables,
                "category": prompt.category,
                "tags": prompt.tags,
                "updatedAt": prompt.updated_at,
            }
        else:
            data = {"content": prompt.content}
        
        with open(filepath, "w") as f:
            json.dump(data, f, indent=2)
    else:
        with open(filepath, "w") as f:
            f.write(prompt.content)

    return filepath


def cmd_init(args: argparse.Namespace) -> None:
    """Initialize config file."""
    config_path = Path.cwd() / CONFIG_FILE
    
    if config_path.exists():
        log_warning(f"{CONFIG_FILE} already exists")
        return

    config = {
        **DEFAULT_CONFIG,
        "apiKey": "${PROMPTCANVAS_API_KEY}",
    }

    with open(config_path, "w") as f:
        json.dump(config, f, indent=2)

    log_success(f"Created {CONFIG_FILE}")
    log_info("Set your API key in the config file or as PROMPTCANVAS_API_KEY environment variable")
    log_info(f"Prompts will be saved to: {config['outputDir']}/")


def cmd_pull(args: argparse.Namespace) -> None:
    """Pull a specific prompt or all prompts."""
    config = load_config()
    api_key = get_api_key(config)

    client = PromptCanvas(api_key=api_key)

    if args.all:
        # Pull all prompts
        log_info("Fetching all production prompts...")

        try:
            result = client.list(limit=100)
            
            if result.total == 0:
                log_warning("No production prompts found")
                return

            log_info(f"Found {result.total} production prompt(s)")

            # Filter to only prompts with production versions
            production_slugs = [p.slug for p in result.prompts if p.has_production]

            if not production_slugs:
                log_warning("No prompts have production versions")
                return

            # Batch fetch all prompts
            batch_result = client.get_many(production_slugs, skip_cache=True)

            success_count = 0
            for prompt in batch_result.prompts:
                filepath = save_prompt(prompt, config)
                rel_path = filepath.relative_to(Path.cwd())
                log_success(f"{prompt.slug} → {rel_path}")
                success_count += 1

            for error in batch_result.errors:
                log_error(f"{error['slug']}: {error['error']}")

            print()
            print(f"{Colors.BOLD}Summary:{Colors.RESET} {success_count} pulled, {len(batch_result.errors)} failed")

        except Exception as e:
            log_error(f"Failed to pull prompts: {e}")
            sys.exit(1)
    else:
        # Pull single prompt
        slug = args.slug
        if not slug:
            log_error("Please specify a prompt slug or use --all")
            print("  Example: promptcanvas pull system-prompt")
            print("  Example: promptcanvas pull --all")
            sys.exit(1)

        log_info(f"Pulling prompt: {slug}")

        try:
            prompt = client.get(slug, skip_cache=True)
            filepath = save_prompt(prompt, config)
            rel_path = filepath.relative_to(Path.cwd())
            log_success(f"Saved: {rel_path}")
            print(f"  {Colors.DIM}Version: {prompt.version} | Updated: {prompt.updated_at}{Colors.RESET}")

        except Exception as e:
            log_error(f'Failed to pull "{slug}": {e}')
            sys.exit(1)


def cmd_list(args: argparse.Namespace) -> None:
    """List available prompts."""
    config = load_config()
    api_key = get_api_key(config)

    client = PromptCanvas(api_key=api_key)

    log_info("Fetching available prompts...")

    try:
        result = client.list(limit=100)

        if result.total == 0:
            log_warning("No prompts found")
            return

        print()
        print(f"{Colors.BOLD}Available Prompts ({result.total}):{Colors.RESET}")
        print()

        for prompt in result.prompts:
            status = f"{Colors.GREEN}●{Colors.RESET}" if prompt.has_production else f"{Colors.YELLOW}○{Colors.RESET}"
            category = f" {Colors.DIM}[{prompt.category}]{Colors.RESET}" if prompt.category else ""
            print(f"  {status} {prompt.slug}{category}")

        print()
        print(f"{Colors.DIM}● = has production version, ○ = no production version{Colors.RESET}")

    except Exception as e:
        log_error(f"Failed to list prompts: {e}")
        sys.exit(1)


def main() -> None:
    """Main CLI entry point."""
    parser = argparse.ArgumentParser(
        prog="promptcanvas",
        description="Pull production prompts from PromptCanvas and store them locally.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  promptcanvas init                  Initialize config file
  promptcanvas pull system-prompt    Pull a single prompt
  promptcanvas pull --all            Pull all production prompts
  promptcanvas list                  List available prompts

Configuration:
  Create a promptcanvas.json file in your project root:
  
  {
    "apiKey": "your-api-key",     // Or use PROMPTCANVAS_API_KEY env var
    "outputDir": "prompts",       // Where to save prompts
    "format": "json",             // "json" or "txt"
    "includeMetadata": true       // Include version, variables, etc.
  }

Environment Variables:
  PROMPTCANVAS_API_KEY    Your PromptCanvas API key (overrides config file)
""",
    )

    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    # init command
    subparsers.add_parser("init", help="Initialize promptcanvas.json config file")

    # pull command
    pull_parser = subparsers.add_parser("pull", help="Pull prompts from PromptCanvas")
    pull_parser.add_argument("slug", nargs="?", help="Prompt slug to pull")
    pull_parser.add_argument(
        "--all", "-a", action="store_true", help="Pull all production prompts"
    )

    # list command
    subparsers.add_parser("list", help="List available prompts")

    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        return

    if args.command == "init":
        cmd_init(args)
    elif args.command == "pull":
        cmd_pull(args)
    elif args.command == "list":
        cmd_list(args)


if __name__ == "__main__":
    main()
