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

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

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

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


# Global epilog text for help output
_EPILOG = """
Examples:
  bunny2fmc --setup             # First time setup with interactive prompts
  bunny2fmc                     # Run sync (default if no arguments)
  bunny2fmc --run               # Explicit run command
  bunny2fmc --show-config       # View current settings
  bunny2fmc --clear-config      # Reset all credentials and configuration

Interactive Setup Prompts:
  • FMC IP Address (e.g., 192.168.3.122) - automatically prepends https://
  • FMC Username (account with API access)
  • FMC Password (stored securely in OS Keyring)
  • Dynamic Object Name (create or select in FMC)
  • Include IPv6? (yes/no - include IPv6 endpoint ranges)
  • Sync Interval (minutes - for cron job scheduling)

Cron Scheduling Examples (after setup):
  */5 * * * *    bunny2fmc      # Every 5 minutes
  */15 * * * *   bunny2fmc      # Every 15 minutes
  0 3 * * *      bunny2fmc      # Daily at 3 AM

Documentation & Support:
  GitHub:  https://github.com/IronKeyVault/Bunny_Sync_FMC
  PyPI:    https://pypi.org/project/bunny2fmc/
  Logs:    ~/.local/share/bunny2fmc/logs/bunny2fmc.log
  Config:  ~/.local/share/bunny2fmc/config.json

Credentials Security:
  All credentials stored securely in OS Keyring (never plain text):
  • Linux:   Secret Service (D-Bus)
  • macOS:   Keychain
  • Windows: Credential Manager
"""


def setup_logging(log_file):
    """Configure logging with file rotation (10 MB per file, max 5 backups)"""
    log_format = "%(asctime)s  %(levelname)s  %(name)s  %(message)s"
    
    logger = logging.getLogger("bunny2fmc")
    logger.setLevel(logging.INFO)

    file_handler = RotatingFileHandler(
        log_file,
        maxBytes=10 * 1024 * 1024,
        backupCount=5,
    )
    file_handler.setLevel(logging.INFO)
    file_handler.setFormatter(logging.Formatter(log_format))
    logger.addHandler(file_handler)

    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."""
    print("\n" + "=" * 60)
    print("bunny2fmc - Initial Configuration")
    print("=" * 60)
    print("Enter your FMC and Bunny configuration.\n")

    while True:
        fmc_ip = input("Enter FMC IP Address (e.g., 192.168.3.122): ").strip()
        if fmc_ip:
            fmc_base_url = f"https://{fmc_ip}"
            break
        print("FMC IP Address cannot be empty.")

    while True:
        fmc_username = input("Enter FMC Username: ").strip()
        if fmc_username:
            break
        print("FMC Username cannot be empty.")

    while True:
        fmc_password = input("Enter FMC Password: ").strip()
        if fmc_password:
            break
        print("FMC Password cannot be empty.")

    while True:
        fmc_dynamic_name = input("Enter Dynamic Object Name (e.g., BunnyCDN_Dynamic): ").strip()
        if fmc_dynamic_name:
            break
        print("Dynamic Object Name cannot be empty.")

    include_ipv6_str = input("Include IPv6 endpoints? (y/n, default: n): ").strip().lower()
    include_ipv6 = include_ipv6_str in ("y", "yes", "1", "true")

    while True:
        interval_str = input("Sync interval in minutes (e.g., 15): ").strip()
        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.")

    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:
        CredentialManager.set_credentials(
            config["fmc_base_url"],
            config["fmc_username"],
            config["fmc_password"],
            config["sync_interval_minutes"],
        )
        ConfigManager.save_dynamic_object_name(config["fmc_dynamic_name"])
        ConfigManager.save_include_ipv6(config["include_ipv6"])

        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_run(args, logger):
    """Handle --run flag or normal execution"""
    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)

    fmc_dynamic_name = ConfigManager.load_dynamic_object_name()
    if not fmc_dynamic_name:
        logger.error("No Dynamic Object name configured. Run: bunny2fmc --setup")
        print("Error: No Dynamic Object name configured.\nPlease run: bunny2fmc --setup")
        sys.exit(1)

    include_ipv6 = ConfigManager.load_include_ipv6()

    logger.info("Starting bunny2fmc sync")
    logger.info("Dynamic Object: %s", fmc_dynamic_name)

    result = sync(
        fmc_base_url=creds["fmc_base_url"],
        fmc_username=creds["fmc_username"],
        fmc_password=creds["fmc_password"],
        dynamic_object_name=fmc_dynamic_name,
        include_ipv6=include_ipv6,
        verify_ssl=True,
        dry_run=False,
        chunk_size=500,
    )

    if result["status"] == "success":
        logger.info("Sync completed: +%d -%d (total: %d)", result["added"], result["removed"], result["total_desired"])
        print(f"\n✓ Sync completed successfully!\n  Added:   {result['added']}\n  Removed: {result['removed']}\n  Total:   {result['total_desired']}")
        sys.exit(0)
    else:
        logger.error("Sync failed: %s", result["message"])
        print(f"\n✗ Sync failed: {result['message']}")
        sys.exit(1)


def cmd_show_config(args, logger):
    """Handle --show-config flag"""
    creds = CredentialManager.get_credentials()
    if not creds:
        print("No configuration found. Run: bunny2fmc --setup")
        return

    fmc_dynamic_name = ConfigManager.load_dynamic_object_name()
    include_ipv6 = ConfigManager.load_include_ipv6()

    print("\n" + "=" * 60)
    print("Current Configuration:")
    print("=" * 60)
    print(f"FMC Base URL:        {creds['fmc_base_url']}")
    print(f"FMC Username:        {creds['fmc_username']}")
    print(f"Dynamic Object Name: {fmc_dynamic_name}")
    print(f"Include IPv6:        {include_ipv6}")
    print(f"Sync Interval:       {creds['sync_interval_minutes']} minute(s)")
    print("=" * 60 + "\n")


def cmd_clear_config(args, logger):
    """Handle --clear-config flag"""
    confirm = input("Are you sure you want to clear all stored configuration? (y/n): ").strip().lower()
    if confirm not in ("y", "yes"):
        print("Cancelled.")
        return

    try:
        CredentialManager.clear_credentials()
        print("✓ Configuration cleared.")
    except Exception as e:
        logger.error("Failed to clear configuration: %s", e)
        print(f"✗ Failed to clear configuration: {e}")


def main():
    """Main entry point with comprehensive help"""
    parser = argparse.ArgumentParser(
        prog="bunny2fmc",
        description="Sync BunnyCDN edge IPs to Cisco FMC Dynamic Objects with secure credential management",
        epilog=_EPILOG,
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument("--version", action="version", version=f"%(prog)s {bunny2fmc.__version__}")
    parser.add_argument("--setup", action="store_true", help="Interactive setup: Configure FMC credentials, Dynamic Object name, IPv6 option, and sync interval")
    parser.add_argument("--run", action="store_true", help="Execute sync immediately using stored credentials")
    parser.add_argument("--show-config", action="store_true", help="Display current configuration (FMC, Dynamic Object name, interval, etc.)")
    parser.add_argument("--clear-config", action="store_true", help="Clear all credentials and configuration")

    args = parser.parse_args()

    ConfigManager.ensure_directories()
    log_file = ConfigManager.get_log_file()
    logger = setup_logging(log_file)

    logger.info("bunny2fmc started with args: %s", sys.argv[1:])

    if args.setup:
        cmd_setup(args)
    elif args.show_config:
        cmd_show_config(args, logger)
    elif args.clear_config:
        cmd_clear_config(args, logger)
    elif args.run or len(sys.argv) == 1:
        cmd_run(args, logger)
    else:
        parser.print_help()
        sys.exit(1)


if __name__ == "__main__":
    main()
