#!/usr/bin/python3
import click
import os
import sys
from typing import Optional

# Import installer functions
from swai_inst.installer import (
    install_from_file, 
    install_from_url, 
    remove_from_app_id,
    remove_bundle_from_id
)
from swai_inst.updater import (
    update_app_from_app_id,
    update_bundle_from_id,
    update_all,
    check_for_updates
)
from swai_inst.utils import (
    get_installed_app_ids,
    get_installed_bundle_ids,
    is_bundle_file,
    set_share_directory
)
from swai_inst.exceptions import SwaiError, SwaiBundleError

@click.group()
@click.option('--local', is_flag=True, help='Install/remove/update for current user only')
@click.option(
    '--share-directory',
    type=click.Path(file_okay=False, path_type=str),
    help='Use a custom share root (contains swai, applications, and icons)'
)
@click.option('--quiet/--verbose', default=None, help='Disable verbose output (default: verbose is on)')
@click.pass_context
def cli(ctx, local, share_directory, quiet):
    """SWAI Installer - Manage SWAI applications"""
    ctx.ensure_object(dict)
    ctx.obj['LOCAL'] = local
    ctx.obj['SHARE_DIRECTORY'] = share_directory
    set_share_directory(share_directory)
    # Verbose is True by default, unless --quiet is specified
    ctx.obj['VERBOSE'] = not quiet if quiet is not None else True

@cli.command()
@click.argument('source')
@click.option(
    '--share-directory',
    type=click.Path(file_okay=False, path_type=str),
    help='Use a custom share root (contains swai, applications, and icons)'
)
@click.pass_context
def install(ctx, source, share_directory):
    """Install a SWAI application or bundle from a file or URL"""
    if share_directory:
        ctx.obj['SHARE_DIRECTORY'] = share_directory
        set_share_directory(share_directory)

    # Check for root privileges if not doing a local install
    if not ctx.obj['LOCAL'] and not ctx.obj['SHARE_DIRECTORY'] and os.getuid() != 0:
        click.echo("Error: Root privileges required for system-wide installation. Use --local flag for user installation or run with sudo.", err=True)
        sys.exit(1)
    
    is_bundle = is_bundle_file(source)
        
    try:
        # Check if source is a URL
        if source.startswith(('http://', 'https://')):
            if ctx.obj['VERBOSE']:
                click.echo(f"Installing {'bundle' if is_bundle else 'app'} from URL: {source}")
            result = install_from_url(source, local_install=ctx.obj['LOCAL'], verbose=ctx.obj['VERBOSE'])
        # Check if source is a file
        elif os.path.isfile(source):
            if ctx.obj['VERBOSE']:
                click.echo(f"Installing {'bundle' if is_bundle else 'app'} from file: {source}")
            result = install_from_file(source, local_install=ctx.obj['LOCAL'], verbose=ctx.obj['VERBOSE'])
        else:
            click.echo("Error: Source must be a valid file path or URL", err=True)
            sys.exit(1)
        
        # Handle different return types for apps vs bundles
        if is_bundle:
            bundle_name, bundle_id, installed_apps = result
            click.echo(f"Successfully installed bundle '{bundle_name}' (ID: {bundle_id})")
            click.echo(f"  Installed {len(installed_apps)} app(s):")
            for app_name, app_id in installed_apps:
                click.echo(f"    - {app_name} (ID: {app_id})")
        else:
            app_name, app_id = result
            click.echo(f"Successfully installed {app_name} (ID: {app_id})")
    except (SwaiError, SwaiBundleError) as e:
        click.echo(f"SWAI Error: {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"Unexpected error installing: {e}", err=True)
        sys.exit(1)

@cli.command()
@click.argument('id')
@click.option('--bundle', '-b', is_flag=True, help='Remove a bundle instead of an app')
@click.option('--keep-data', is_flag=True, help='Keep application data when removing')
@click.option('--no-cascade', is_flag=True, help='Do not remove apps that depend on this app')
@click.pass_context
def remove(ctx, id, bundle, keep_data, no_cascade):
    """Remove a SWAI application or bundle by ID
    
    By default, also removes any apps that depend on the removed app (have it in their 'requires' list).
    Use --no-cascade to only remove the specified app.
    """
    # Check for root privileges if not doing a local install
    if not ctx.obj['LOCAL'] and not ctx.obj['SHARE_DIRECTORY'] and os.getuid() != 0:
        click.echo("Error: Root privileges required for system-wide removal. Use --local flag for user removal or run with sudo.", err=True)
        sys.exit(1)
        
    try:
        if bundle:
            if ctx.obj['VERBOSE']:
                click.echo(f"Removing bundle with ID: {id}")
            
            remove_bundle_from_id(
                id,
                local_install=ctx.obj['LOCAL'],
                verbose=ctx.obj['VERBOSE'],
                remove_data=not keep_data
            )
            click.echo(f"Successfully removed bundle (ID: {id})")
        else:
            if ctx.obj['VERBOSE']:
                click.echo(f"Removing application with ID: {id}")
            
            remove_from_app_id(
                id,
                local_install=ctx.obj['LOCAL'],
                verbose=ctx.obj['VERBOSE'],
                remove_data=not keep_data,
                remove_dependents=not no_cascade
            )
            click.echo(f"Successfully removed application (ID: {id})")
    except (SwaiError, SwaiBundleError) as e:
        click.echo(f"SWAI Error: {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"Unexpected error removing: {e}", err=True)
        sys.exit(1)

@cli.command()
@click.argument('id', required=False)
@click.option('--bundle', '-b', is_flag=True, help='Update a bundle instead of an app')
@click.pass_context
def update(ctx, id: Optional[str] = None, bundle: bool = False):
    """Updates all or a specific SWAI application or bundle"""
    # Check for root privileges if not doing a local install
    if not ctx.obj['LOCAL'] and not ctx.obj['SHARE_DIRECTORY'] and os.getuid() != 0:
        click.echo("Error: Root privileges required for system-wide updates. Use --local flag for user updates or run with sudo.", err=True)
        sys.exit(1)
        
    try:
        if id:
            if bundle:
                if ctx.obj['VERBOSE']:
                    click.echo(f"Updating bundle with ID: {id}")
                result = update_bundle_from_id(
                    id,
                    local_install=ctx.obj['LOCAL'],
                    verbose=ctx.obj['VERBOSE']
                )
                if result:
                    click.echo(f"Successfully updated bundle (ID: {id})")
                else:
                    click.echo(f"No update available for bundle (ID: {id})")
            else:
                if ctx.obj['VERBOSE']:
                    click.echo(f"Updating application with ID: {id}")
                result = update_app_from_app_id(
                    id,
                    local_install=ctx.obj['LOCAL'],
                    verbose=ctx.obj['VERBOSE']
                )
                if result:
                    click.echo(f"Successfully updated application (ID: {id})")
                else:
                    click.echo(f"No update available for application (ID: {id})")
        else:
            if ctx.obj['VERBOSE']:
                click.echo("Updating all installed applications and bundles")
            updated_count = update_all(
                local_install=ctx.obj['LOCAL'],
                verbose=ctx.obj['VERBOSE']
            )
            click.echo(f"Successfully updated {updated_count} item(s)")
    except (SwaiError, SwaiBundleError) as e:
        click.echo(f"SWAI Error: {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"Unexpected error updating: {e}", err=True)
        sys.exit(1)

@cli.command()
@click.pass_context
def check_updates(ctx):
    """Check for available updates for all installed SWAI applications and bundles"""
    try:
        if ctx.obj['VERBOSE']:
            click.echo("Checking for updates...")
        
        app_updates, bundle_updates = check_for_updates(
            local_install=ctx.obj['LOCAL'],
            verbose=ctx.obj['VERBOSE']
        )

        has_updates = bool(app_updates or bundle_updates)
        
        if has_updates:
            total_updates = len(app_updates) + len(bundle_updates)
            click.echo(f"Updates available for {total_updates} item(s):")
            
            if app_updates:
                click.echo("\n  Applications:")
                for app_id in app_updates:
                    click.echo(f"    - {app_id}")
            
            if bundle_updates:
                click.echo("\n  Bundles:")
                for bundle_id in bundle_updates:
                    click.echo(f"    - {bundle_id}")
            
            click.echo("\nRun 'update' command to apply updates.")
        else:
            click.echo("All applications and bundles are up to date.")
            
    except (SwaiError, SwaiBundleError) as e:
        click.echo(f"SWAI Error: {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"Unexpected error checking for updates: {e}", err=True)
        sys.exit(1)


@cli.command()
@click.pass_context
def list_installed(ctx):
    """List all installed SWAI applications and bundles"""
    try:
        app_ids = get_installed_app_ids(local_install=ctx.obj['LOCAL'])
        bundle_ids = get_installed_bundle_ids(local_install=ctx.obj['LOCAL'])
        
        if not app_ids and not bundle_ids:
            click.echo("No SWAI applications or bundles installed.")
            return
        
        if app_ids:
            click.echo(f"Installed applications ({len(app_ids)}):")
            for app_id in sorted(app_ids):
                click.echo(f"  - {app_id}")
        
        if bundle_ids:
            click.echo(f"\nInstalled bundles ({len(bundle_ids)}):")
            for bundle_id in sorted(bundle_ids):
                click.echo(f"  - {bundle_id}")
                
    except Exception as e:
        click.echo(f"Error listing installed items: {e}", err=True)
        sys.exit(1)


if __name__ == '__main__':
    cli(obj={})
