"""Volumes command group - Manage storage volumes."""

import re
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Any, Optional, Tuple

import click
from rich.table import Table

from flow import Flow
from flow.errors import AuthenticationError

from .base import BaseCommand, console


class VolumesCommand(BaseCommand):
    """Manage storage volumes."""

    @property
    def name(self) -> str:
        return "volumes"

    @property
    def help(self) -> str:
        return "Manage storage volumes"

    def get_command(self) -> click.Group:
        """Return the volumes command group."""
        @click.group(name=self.name, help=self.help)
        def volumes():
            """Manage storage volumes."""
            pass

        # Add subcommands
        volumes.add_command(self._list_command())
        volumes.add_command(self._create_command())
        volumes.add_command(self._delete_command())
        volumes.add_command(self._delete_all_command())

        return volumes

    def _list_command(self) -> click.Command:
        @click.command(name="list")
        def volumes_list():
            """List all volumes."""
            try:
                flow_client = Flow(auto_init=True)

                volumes = flow_client.list_volumes()
                if not volumes:
                    console.print("No volumes found.", style="yellow")
                    return

                table = Table(show_header=True, header_style="bold")
                table.add_column("Volume ID", style="cyan")
                table.add_column("Name")
                table.add_column("Size (GB)", justify="right")
                table.add_column("Status")
                table.add_column("Created", style="dim")

                for volume in volumes:
                    table.add_row(
                        volume.id,
                        volume.name or "-",
                        str(volume.size_gb),
                        "[green]available[/green]",  # Volumes are always available in the domain model
                        volume.created_at.strftime("%Y-%m-%d %H:%M") if volume.created_at else "-",
                    )

                console.print(table)

            except AuthenticationError:
                self.handle_auth_error()
            except Exception as e:
                self.handle_error(str(e))

        return volumes_list

    def _create_command(self) -> click.Command:
        @click.command(name="create")
        @click.option("--size", "-s", type=int, required=True, help="Volume size in GB")
        @click.option("--name", "-n", help="Optional name for the volume")
        def volumes_create(size: int, name: Optional[str]):
            """Create a new volume."""
            try:
                flow_client = Flow(auto_init=True)

                console.print(f"Creating {size}GB volume...")
                volume = flow_client.create_volume(size_gb=size, name=name)

                console.print(f"[green]✓[/green] Volume created: [cyan]{volume.id}[/cyan]")
                if name:
                    console.print(f"Name: {name}")

            except AuthenticationError:
                self.handle_auth_error()
            except Exception as e:
                self.handle_error(str(e))

        return volumes_create

    def _delete_command(self) -> click.Command:
        @click.command(name="delete")
        @click.argument("volume_id")
        @click.option("--yes", "-y", is_flag=True, help="Skip confirmation")
        def volumes_delete(volume_id: str, yes: bool):
            """Delete a volume."""
            try:
                if not yes:
                    confirm = click.confirm(f"Delete volume {volume_id}?")
                    if not confirm:
                        console.print("Cancelled")
                        return

                flow_client = Flow(auto_init=True)
                flow_client.delete_volume(volume_id)
                console.print(f"[green]✓[/green] Volume {volume_id} deleted")

            except AuthenticationError:
                self.handle_auth_error()
            except Exception as e:
                self.handle_error(str(e))

        return volumes_delete

    def _delete_all_command(self) -> click.Command:
        @click.command(name="delete-all")
        @click.option("--pattern", "-p", help="Only delete volumes matching pattern")
        @click.option("--dry-run", is_flag=True, help="Show what would be deleted")
        @click.option("--yes", "-y", is_flag=True, help="Skip confirmation")
        def volumes_delete_all(pattern: Optional[str], dry_run: bool, yes: bool):
            """Delete all volumes (with optional pattern matching)."""
            try:
                flow_client = Flow(auto_init=True)

                volumes = flow_client.list_volumes()
                if not volumes:
                    console.print("No volumes found.")
                    return

                # Filter by pattern if provided
                to_delete = []
                for volume in volumes:
                    if pattern:
                        # Try regex matching first, fall back to substring matching
                        try:
                            regex = re.compile(pattern)
                            if regex.search(volume.id) or (volume.name and regex.search(volume.name)):
                                to_delete.append(volume)
                        except re.error:
                            # If not a valid regex, use substring matching
                            if pattern in volume.id or (volume.name and pattern in volume.name):
                                to_delete.append(volume)
                    else:
                        to_delete.append(volume)

                if not to_delete:
                    console.print(f"No volumes found matching pattern: {pattern}")
                    return

                # Show what will be deleted
                console.print(f"Found {len(to_delete)} volume(s) to delete:")
                for volume in to_delete:
                    name_str = f" ({volume.name})" if volume.name else ""
                    console.print(f"  - {volume.id}{name_str}")

                if dry_run:
                    console.print("\n[yellow]Dry run - no volumes deleted[/yellow]")
                    return

                # Confirm deletion
                if not yes:
                    confirm = click.confirm(f"\nDelete {len(to_delete)} volume(s)?")
                    if not confirm:
                        console.print("Cancelled")
                        return

                # Delete volumes in parallel
                deleted = 0
                failed = 0

                def delete_volume(volume: Any) -> Tuple[str, bool, Optional[str]]:
                    """Delete a single volume and return (id, success, error_msg)."""
                    try:
                        flow_client.delete_volume(volume.id)
                        return volume.id, True, None
                    except Exception as e:
                        return volume.id, False, str(e)

                # Use ThreadPoolExecutor for parallel deletion
                # Limit to 10 concurrent deletions to avoid overwhelming the API
                max_workers = min(10, len(to_delete))

                with ThreadPoolExecutor(max_workers=max_workers) as executor:
                    # Submit all deletion tasks
                    future_to_volume = {
                        executor.submit(delete_volume, volume): volume
                        for volume in to_delete
                    }

                    # Process results as they complete
                    for future in as_completed(future_to_volume):
                        volume_id, success, error_msg = future.result()
                        if success:
                            console.print(f"[green]✓[/green] Deleted {volume_id}")
                            deleted += 1
                        else:
                            console.print(f"[red]✗[/red] Failed to delete {volume_id}: {error_msg}")
                            failed += 1

                # Summary
                console.print(f"\nDeleted {deleted} volume(s)")
                if failed > 0:
                    console.print(f"[red]Failed to delete {failed} volume(s)[/red]")

            except AuthenticationError:
                self.handle_auth_error()
            except Exception as e:
                self.handle_error(str(e))

        return volumes_delete_all


# Export command instance
command = VolumesCommand()
