#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
bunny2fmc CLI: Main entry point with argparse, credential management, and logging
"""

import argparse
import getpass
import logging
import sys
from logging.handlers import RotatingFileHandler

import bunny2fmc
from bunny2fmc.config import CredentialManager, ConfigManager
from bunny2fmc.sync_engine import sync

# Global epilog text for help output
_EPILOG = """
Examples:

  # First time setup (interactive)
  bunny2fmc --setup

  # Run sync once
  bunny2fmc --run

  # Show current config
  bunny2fmc --config

  # Clear all config
  bunny2fmc --clear

Setup Instructions:

  1. Activate your virtual environment (if using venv):
     source /path/to/venv/bin/activate    # Linux/macOS
     .\\venv\\Scripts\\activate         # Windows

  2. Run the setup wizard:
     bunny2fmc --setup

  3. When prompted, enter your FMC details and sync interval

  4. Credentials are stored securely in your OS keyring (not in files)

  5. To run on a schedule, add to crontab:
     */15 * * * * bunny2fmc --run    # Every 15 minutes

For detailed info: bunny2fmc --help
"""


def setup_logging():
    """Configure logging with rotating file handler"""
    logger = logging.getLogger("bunny2fmc")
    logger.setLevel(logging.INFO)

    config_dir = ConfigManager.get_config_dir()
    log_file = ConfigManager.get_log_file()

    log_format = "[%(asctime)s] %(levelname)-8s %(name)s  %(message)s"

    # Rotating file handler (10 MB per file)
    file_handler = RotatingFileHandler(
        log_file,
        maxBytes=10 * 1024 * 1024,  # 10 MB
        backupCount=5,
    )
    file_handler.setLevel(logging.INFO)
    file_handler.setFormatter(logging.Formatter(log_format))
    logger.addHandler(file_handler)

    # Console handler (for interactive mode)
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
    console_handler.setFormatter(logging.Formatter(log_format))
    logger.addHandler(console_handler)

    return logger


def interactive_setup():
    """
    Interactive setup: prompt for credentials and interval.
    Loads previous values as defaults. Password is hidden.
    Returns dict with configuration.
    """
    print("\n" + "=" * 60)
    print("bunny2fmc - Configuration")
    print("=" * 60)
    print("Enter your FMC and Bunny configuration.\n")

    # Try to load previous configuration
    try:
        previous_url = ConfigManager.load_fmc_base_url()
        previous_username = ConfigManager.load_fmc_username()
        previous_dynamic = ConfigManager.load_dynamic_object_name()
        previous_ipv6 = ConfigManager.load_include_ipv6()
        previous_interval = ConfigManager.load_sync_interval_minutes()
        # Check if password is already stored in keyring
        has_stored_password = CredentialManager.get_credentials() is not None
    except Exception:
        previous_url = None
        previous_username = None
        previous_dynamic = None
        previous_ipv6 = False
        previous_interval = None
        has_stored_password = False

    # Extract IP from URL (remove https://)
    previous_ip = None
    if previous_url:
        previous_ip = previous_url.replace("https://", "").replace("http://", "")

    # FMC IP Address
    while True:
        prompt = f"Enter FMC IP Address"
        if previous_ip:
            prompt += f" [{previous_ip}]"
        else:
            prompt += " (e.g., 192.168.3.122)"
        prompt += ": "

        fmc_ip = input(prompt).strip()

        # Use previous IP if user just presses Enter
        if not fmc_ip and previous_ip:
            fmc_ip = previous_ip

        if fmc_ip:
            # Automatically prepend https://
            fmc_base_url = f"https://{fmc_ip}"
            break
        print("FMC IP Address cannot be empty.")

    # FMC Username
    while True:
        prompt = f"Enter FMC Username"
        if previous_username:
            prompt += f" [{previous_username}]"
        prompt += ": "

        fmc_username = input(prompt).strip()

        # Use previous username if user just presses Enter
        if not fmc_username and previous_username:
            fmc_username = previous_username

        if fmc_username:
            break
        print("FMC Username cannot be empty.")

    # FMC Password (hidden input)
    while True:
        if has_stored_password:
            password_prompt = "Enter FMC Password (or press Enter to use stored password): "
        else:
            password_prompt = "Enter FMC Password: "

        fmc_password = getpass.getpass(password_prompt)

        # If user pressed Enter and we have a stored password, retrieve it
        if not fmc_password and has_stored_password:
            creds = CredentialManager.get_credentials()
            if creds:
                fmc_password = creds.get("fmc_password")

        if fmc_password:
            break

        if has_stored_password:
            print("Please enter a password or press Enter to use the stored one.")
        else:
            print("FMC Password cannot be empty.")

    # Dynamic Object Name
    while True:
        prompt = f"Enter Dynamic Object Name"
        if previous_dynamic:
            prompt += f" [{previous_dynamic}]"
        else:
            prompt += " (e.g., BunnyCDN_Dynamic)"
        prompt += ": "

        fmc_dynamic_name = input(prompt).strip()

        # Use previous dynamic name if user just presses Enter
        if not fmc_dynamic_name and previous_dynamic:
            fmc_dynamic_name = previous_dynamic

        if fmc_dynamic_name:
            break
        print("Dynamic Object Name cannot be empty.")

    # Include IPv6
    default_ipv6_str = "y" if previous_ipv6 else "n"
    include_ipv6_str = input(
        f"Include IPv6 endpoints? (y/n, default: {default_ipv6_str}): "
    ).strip().lower()

    if not include_ipv6_str:
        include_ipv6 = previous_ipv6
    else:
        include_ipv6 = include_ipv6_str in ("y", "yes", "1", "true")

    # Sync interval in minutes
    while True:
        prompt = f"Sync interval in minutes"
        if previous_interval:
            prompt += f" [{previous_interval}]"
        else:
            prompt += " (e.g., 15)"
        prompt += ": "

        interval_str = input(prompt).strip()

        # Use previous interval if user just presses Enter
        if not interval_str and previous_interval:
            interval_str = str(previous_interval)

        try:
            sync_interval_minutes = int(interval_str)
            if sync_interval_minutes > 0:
                break
            print("Interval must be a positive number.")
        except ValueError:
            print("Interval must be a valid integer.")

    # Confirm
    print("\n" + "-" * 60)
    print("Configuration Summary:")
    print(f"  FMC URL:              {fmc_base_url}")
    print(f"  FMC Username:         {fmc_username}")
    print(f"  Dynamic Object Name:  {fmc_dynamic_name}")
    print(f"  Include IPv6:         {include_ipv6}")
    print(f"  Sync Interval:        {sync_interval_minutes} minute(s)")
    print("-" * 60)

    confirm = input("\nSave this configuration? (y/n): ").strip().lower()
    if confirm not in ("y", "yes"):
        print("Setup cancelled.")
        return None

    return {
        "fmc_base_url": fmc_base_url,
        "fmc_username": fmc_username,
        "fmc_password": fmc_password,
        "fmc_dynamic_name": fmc_dynamic_name,
        "include_ipv6": include_ipv6,
        "sync_interval_minutes": sync_interval_minutes,
    }


def cmd_setup(args):
    """Handle --setup flag"""
    config = interactive_setup()
    if not config:
        sys.exit(1)

    try:
        # Store credentials in keyring
        CredentialManager.set_credentials(
            config["fmc_base_url"],
            config["fmc_username"],
            config["fmc_password"],
            config["sync_interval_minutes"],
        )

        # Store config values in config.json (URL, username, dynamic name, IPv6, interval)
        ConfigManager.save_fmc_base_url(config["fmc_base_url"])
        ConfigManager.save_fmc_username(config["fmc_username"])
        ConfigManager.save_dynamic_object_name(config["fmc_dynamic_name"])
        ConfigManager.save_include_ipv6(config["include_ipv6"])
        ConfigManager.save_sync_interval_minutes(config["sync_interval_minutes"])

        print("\n✓ Configuration saved securely!")
        print(f"\nYou can now run: bunny2fmc")
        print(f"\nTo run the sync immediately:")
        print(f"  bunny2fmc --run")
        print(f"\nTo schedule with cron (for {config['sync_interval_minutes']} minute interval):")
        print(f"  */{config['sync_interval_minutes']} * * * * bunny2fmc --run")
        sys.exit(0)
    except Exception as e:
        print(f"\n✗ Failed to save configuration: {e}")
        sys.exit(1)


def cmd_show_config(args):
    """Handle --config flag: show current configuration"""
    try:
        # Load config
        fmc_url = ConfigManager.load_fmc_base_url()
        fmc_username = ConfigManager.load_fmc_username()
        fmc_dynamic = ConfigManager.load_dynamic_object_name()
        include_ipv6 = ConfigManager.load_include_ipv6()
        sync_interval = ConfigManager.load_sync_interval_minutes()

        if not all([fmc_url, fmc_username, fmc_dynamic, sync_interval is not None]):
            print("No configuration found. Run: bunny2fmc --setup")
            sys.exit(1)

        print("\nCurrent Configuration:")
        print("-" * 60)
        print(f"  FMC URL:              {fmc_url}")
        print(f"  FMC Username:         {fmc_username}")
        print(f"  Dynamic Object Name:  {fmc_dynamic}")
        print(f"  Include IPv6:         {include_ipv6}")
        print(f"  Sync Interval:        {sync_interval} minute(s)")
        print("-" * 60)
        print("\n✓ Credentials are stored securely in your OS keyring.")
        print(f"\nLog file: {ConfigManager.get_log_file()}")
        sys.exit(0)
    except Exception as e:
        print(f"Error: {e}")
        sys.exit(1)


def cmd_clear_config(args):
    """Handle --clear flag: clear all stored configuration"""
    confirm = input(
        "\nWarning: This will clear all stored credentials and configuration.\n"
        "Continue? (y/n): "
    ).strip().lower()
    if confirm not in ("y", "yes"):
        print("Cancelled.")
        sys.exit(0)

    try:
        CredentialManager.clear_credentials()
        config_file = ConfigManager.get_config_dir() / "config.json"
        if config_file.exists():
            config_file.unlink()
        print("✓ Configuration cleared.")
        sys.exit(0)
    except Exception as e:
        print(f"Error: {e}")
        sys.exit(1)


def cmd_run(args, logger):
    """Handle --run flag or normal execution"""
    # Load credentials from keyring
    creds = CredentialManager.get_credentials()
    if not creds:
        logger.error("No stored credentials found. Run: bunny2fmc --setup")
        print("Error: No stored credentials found.\nPlease run: bunny2fmc --setup")
        sys.exit(1)

    # Load additional config
    fmc_dynamic_name = ConfigManager.load_dynamic_object_name()
    include_ipv6 = ConfigManager.load_include_ipv6()

    if not fmc_dynamic_name:
        logger.error("Dynamic Object name not configured. Run: bunny2fmc --setup")
        print(
            "Error: Dynamic Object name not configured.\n"
            "Please run: bunny2fmc --setup"
        )
        sys.exit(1)

    # Run the sync
    try:
        logger.info(
            f"Starting sync (IPv6: {include_ipv6}, Dynamic Object: {fmc_dynamic_name})"
        )
        sync(
            fmc_base_url=creds["fmc_base_url"],
            fmc_username=creds["fmc_username"],
            fmc_password=creds["fmc_password"],
            fmc_dynamic_name=fmc_dynamic_name,
            include_ipv6=include_ipv6,
            logger=logger,
        )
        logger.info("Sync completed successfully")
        print("✓ Sync completed successfully")
        sys.exit(0)
    except Exception as e:
        logger.error(f"Sync failed: {e}")
        print(f"Error: {e}")
        sys.exit(1)


def main():
    """Main entry point with argparse"""
    parser = argparse.ArgumentParser(
        prog="bunny2fmc",
        description="Sync BunnyCDN IP list to Cisco FMC Dynamic Objects",
        epilog=_EPILOG,
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        "--version",
        action="version",
        version=f"%(prog)s {bunny2fmc.__version__}",
        help="Show version and exit",
    )

    parser.add_argument(
        "--setup",
        action="store_true",
        help="Run interactive setup wizard",
    )

    parser.add_argument(
        "--config",
        action="store_true",
        help="Show current configuration",
    )

    parser.add_argument(
        "--clear",
        action="store_true",
        help="Clear all stored configuration and credentials",
    )

    parser.add_argument(
        "--run",
        action="store_true",
        help="Run sync immediately (can also just run 'bunny2fmc')",
    )

    args = parser.parse_args()

    # Setup logging
    logger = setup_logging()
    logger.info(f"bunny2fmc started with args: {sys.argv[1:]}")

    # Handle commands
    if args.setup:
        cmd_setup(args)
    elif args.config:
        cmd_show_config(args)
    elif args.clear:
        cmd_clear_config(args)
    else:
        # Default: run sync
        cmd_run(args, logger)


if __name__ == "__main__":
    main()
