"""
Billing drop composition and management CLI commands.

Provides commands for:
- billing-drop list: Show all organizations with billing drops
- billing-drop describe: Show detailed composition analysis
- billing-drop history: Show upload history for an organization
- billing-drop explore: Progressive drill-down into billing drops
"""

from typing import Optional

import typer
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich import box

from src.services.environment_service import EnvironmentService
from src.services.s3_data_service import S3DataService
from src.services.dataset_identification import (
    DatasetMetadataService,
    UploadTrackingService,
    BillingDropService
)

console = Console()
app = typer.Typer(
    name="billing-drop",
    help="Billing drop composition and management commands",
    no_args_is_help=True
)


@app.command("list")
def list_organizations():
    """
    List all organizations with billing drops.

    Shows organizations that have active billing drops with basic information.

    Example:
        czbg billing-drop list
    """
    try:
        # FAIL FAST: Validate AWS credentials
        env_service = EnvironmentService()
        env_service.validate_aws_credentials_and_access()

        # Initialize services
        s3_service = S3DataService()
        upload_tracking = UploadTrackingService(s3_service)
        billing_drop_service = BillingDropService(s3_service, upload_tracking)

        console.print("🏢 [bold blue]Organizations with Billing Drops[/bold blue]")

        # Get all organizations with drops
        organizations = billing_drop_service.list_all_organizations_with_drops()

        if not organizations:
            console.print("[yellow]No organizations with billing drops found.[/yellow]")
            return

        # Create table
        table = Table(show_header=True, header_style="bold blue", box=box.ROUNDED)
        table.add_column("Organization", style="cyan", min_width=15)
        table.add_column("Active Drop", style="yellow", min_width=12)
        table.add_column("Source Dataset", style="green", min_width=20)

        for org in organizations:
            # Get latest upload for this organization
            latest_upload = upload_tracking.get_latest_upload_for_organization(org)

            if latest_upload:
                table.add_row(
                    org,
                    latest_upload.drop_id,
                    latest_upload.dataset_id
                )
            else:
                # Fallback: organization has billing drops but no upload tracking
                table.add_row(
                    org,
                    "Unknown",
                    "Not tracked"
                )

        console.print(table)
        console.print(f"\n[dim]💡 Use: czbg billing-drop history <org> to see upload history[/dim]")

    except ValueError as e:
        console.print(f"❌ {str(e)}")
        raise typer.Exit(1)
    except Exception as e:
        console.print(f"❌ Failed to list organizations: {e}")
        raise typer.Exit(1)


@app.command("history")
def show_organization_history(
    organization: str = typer.Argument(..., help="Organization name")
):
    """
    Show upload history for an organization.

    Displays all upload events for the organization, showing which datasets
    were uploaded when and to which providers.

    Examples:
        czbg billing-drop history DemoTest
        czbg billing-drop history ProdOrg
    """
    try:
        # FAIL FAST: Validate AWS credentials
        env_service = EnvironmentService()
        env_service.validate_aws_credentials_and_access()

        # Initialize services
        s3_service = S3DataService()
        upload_tracking = UploadTrackingService(s3_service)

        console.print(f"📋 [bold blue]Upload History: {organization}[/bold blue]")

        # Get upload history
        upload_events = upload_tracking.get_upload_history(organization)

        if not upload_events:
            console.print(f"[yellow]No upload history found for organization: {organization}[/yellow]")
            return

        # Create table
        table = Table(show_header=True, header_style="bold blue", box=box.ROUNDED)
        table.add_column("Upload Date", style="green", min_width=12)
        table.add_column("Dataset", style="cyan", min_width=20)
        table.add_column("Type", style="yellow", min_width=8)
        table.add_column("Providers", style="magenta", min_width=12)
        table.add_column("Months", style="white", min_width=15)

        for event in upload_events:
            upload_date = event.uploaded_at.strftime("%Y-%m-%d")
            providers_str = ", ".join(event.providers_uploaded)
            months_str = ", ".join(event.months_uploaded)

            # Truncate long strings
            if len(months_str) > 20:
                months_str = months_str[:17] + "..."

            table.add_row(
                upload_date,
                event.dataset_id,
                event.upload_type,
                providers_str,
                months_str
            )

        console.print(table)
        console.print(f"\n[dim]💡 Use: czbg dataset describe <dataset-id> to analyze source datasets[/dim]")

    except ValueError as e:
        console.print(f"❌ {str(e)}")
        raise typer.Exit(1)
    except Exception as e:
        console.print(f"❌ Failed to show history: {e}")
        raise typer.Exit(1)



@app.command("explore")
def explore_billing_drops(
    organization: Optional[str] = typer.Option(None, "--org", help="Organization to explore"),
    provider: Optional[str] = typer.Option(None, "--provider", help="Provider to explore (AWS, GCP, Azure)"),
    date_range: Optional[str] = typer.Option(None, "--date-range", help="Date range to show drops table for (e.g., '20240701-20240801')"),
    drop: Optional[str] = typer.Option(None, "--drop", help="Specific drop ID to show detailed file information for")
):
    """
    Progressive drill-down exploration of billing drops.

    Provides detailed exploration of billing drop structure with filtering options.

    Examples:
        czbg billing-drop explore
        czbg billing-drop explore --org DemoTest
        czbg billing-drop explore --org DemoTest --provider AWS
        czbg billing-drop explore --org DemoTest --provider AWS --date-range 20250301-20250401
        czbg billing-drop explore --org DemoTest --provider AWS --date-range 20250301-20250401 --drop 20250916T190931Z
    """
    try:
        # FAIL FAST: Validate AWS credentials
        env_service = EnvironmentService()
        env_service.validate_aws_credentials_and_access()

        # Initialize services
        s3_service = S3DataService()
        upload_tracking = UploadTrackingService(s3_service)
        billing_drop_service = BillingDropService(s3_service, upload_tracking)

        if not organization:
            # Show all organizations for selection
            _explore_organization_selection(billing_drop_service)
        elif not provider:
            # Show providers for selected organization
            _explore_provider_selection(billing_drop_service, organization)
        elif not date_range:
            # Show date ranges for org/provider
            _explore_date_range_selection(billing_drop_service, organization, provider)
        elif not drop:
            # Show drops table for org/provider/date-range
            _explore_drops_for_date_range(billing_drop_service, organization, provider, date_range)
        else:
            # Show detailed drop information
            _explore_specific_drop_details(billing_drop_service, organization, provider, date_range, drop)

    except ValueError as e:
        console.print(f"❌ {str(e)}")
        raise typer.Exit(1)
    except Exception as e:
        console.print(f"❌ Failed to explore billing drops: {e}")
        raise typer.Exit(1)


def _explore_organization_selection(billing_drop_service):
    """Show organization selection interface."""
    console.print("Available organizations in billing drops:")

    organizations = billing_drop_service.list_all_organizations_with_drops()

    if not organizations:
        console.print("[yellow]No organizations with billing drops found.[/yellow]")
        return

    # Simple bullet list format like list-upload-datasets
    for org in organizations:
        console.print(f"  • {org}")

    console.print(f"\nUse --org to drill down into a specific organization")


def _explore_provider_selection(billing_drop_service, organization):
    """Show provider selection for an organization."""
    console.print(f"Providers for organization '{organization}' in billing drops:")

    providers = billing_drop_service.list_organization_providers(organization)

    if not providers:
        console.print(f"[yellow]No billing drops found for organization: {organization}[/yellow]")
        return

    # Simple bullet list format like list-upload-datasets
    for provider in providers:
        console.print(f"  • {provider}")

    console.print(f"\nUse --provider to drill down into a specific provider")


def _explore_drop_details(billing_drop_service, organization, provider):
    """Show detailed drop information for org/provider."""
    console.print(f"🔍 [bold blue]Organization: {organization} | Provider: {provider}[/bold blue]")

    drops = billing_drop_service.list_organization_drops(organization)
    provider_drops = [drop for drop in drops if drop.provider.upper() == provider.upper()]

    if not provider_drops:
        console.print(f"[yellow]No {provider} billing drops found for {organization}.[/yellow]")
        return

    # Create detailed drops table
    table = Table(show_header=True, header_style="bold blue", box=box.ROUNDED)
    table.add_column("Date Range", style="cyan", min_width=20)
    table.add_column("Drop ID", style="yellow", min_width=15)
    table.add_column("Last Upload", style="green", min_width=12)

    for drop in provider_drops:
        last_upload_str = drop.last_upload.strftime("%Y-%m-%d") if drop.last_upload else "Unknown"

        table.add_row(
            drop.date_range,
            drop.active_drop_id,
            last_upload_str
        )

    console.print(table)
    console.print(f"\n[dim]💡 Use: czbg dataset describe <dataset-id> to analyze source datasets[/dim]")


def _explore_date_range_selection(billing_drop_service, organization, provider):
    """Show date range selection for org/provider."""
    console.print(f"Date ranges for organization '{organization}' provider '{provider}' in billing drops:")

    # Use S3DataService to get date ranges (same as list-upload-datasets)
    from src.services.s3_data_service import S3DataService
    s3_service = S3DataService()

    try:
        date_ranges = s3_service.list_upload_date_ranges(organization, provider)

        if not date_ranges:
            console.print(f"[yellow]No date ranges found for organization '{organization}' provider '{provider}'[/yellow]")
            return

        # Create table for date ranges with Active Drop ID and Dataset ID
        table = Table(show_header=True, header_style="bold magenta")
        table.add_column("Date Range", style="cyan")
        table.add_column("Active Drop ID", style="yellow", min_width=17)
        table.add_column("Dataset ID", style="green", min_width=15)

        for date_range_name in date_ranges:
            # Get active drop ID from manifest
            active_drop_id = billing_drop_service._get_active_drop_id_from_manifest(organization, provider, date_range_name)

            # Get dataset ID from upload tracking if available
            dataset_id = "Not tracked"
            try:
                # Get all upload events for this org and find one that matches this drop ID
                upload_events = billing_drop_service.upload_tracking_service.get_upload_history(organization)
                for upload_event in upload_events:
                    if upload_event.drop_id == active_drop_id:
                        dataset_id = upload_event.dataset_id
                        break
            except:
                pass

            table.add_row(
                date_range_name,
                active_drop_id or "Unknown",
                dataset_id
            )

        console.print(table)
        console.print(f"\nUse --date-range to view drops table for a specific date range")

    except Exception as e:
        console.print(f"[yellow]Error listing date ranges: {e}[/yellow]")


def _explore_drops_for_date_range(billing_drop_service, organization, provider, date_range):
    """Show drops table for org/provider/date-range."""
    console.print(f"Drops for organization '{organization}' provider '{provider}' date range '{date_range}':")

    # Use S3DataService to get drops info (same as list-upload-datasets)
    from src.services.s3_data_service import S3DataService
    s3_service = S3DataService()

    try:
        drops_info = s3_service.list_drops_in_date_range(organization, provider, date_range)

        if not drops_info:
            console.print(f"[yellow]No drops found for organization '{organization}' provider '{provider}' date range '{date_range}'[/yellow]")
            return

        # Create table for drops with Dataset ID column
        table = Table(show_header=True, header_style="bold magenta")
        table.add_column("Drop ID", style="cyan")
        table.add_column("Active", style="green", justify="center")
        table.add_column("Files", style="yellow", justify="right")
        table.add_column("Total Rows", style="blue", justify="right")
        table.add_column("Dataset ID", style="magenta", min_width=15)

        # Get active drop ID from manifest
        active_drop_id = drops_info[0].get("active_drop_id") if drops_info else None

        for drop_info in drops_info:
            drop_id = drop_info["drop_id"]
            is_active = "✓" if drop_id == active_drop_id else ""
            file_count = drop_info["file_count"]
            total_rows = drop_info["total_rows"]

            # Get dataset ID from upload tracking if available
            dataset_id = "Not tracked"
            try:
                # Get all upload events for this org and find one that matches this drop ID
                upload_events = billing_drop_service.upload_tracking_service.get_upload_history(organization)
                for upload_event in upload_events:
                    if upload_event.drop_id == drop_id:
                        dataset_id = upload_event.dataset_id
                        break
            except:
                pass

            table.add_row(
                drop_id,
                is_active,
                f"{file_count:,}" if file_count > 0 else "0",
                f"{total_rows:,}" if total_rows > 0 else "0",
                dataset_id
            )

        console.print(table)
        console.print(f"\nUse --drop to view detailed file information for a specific drop")

    except Exception as e:
        console.print(f"[yellow]Error listing drops: {e}[/yellow]")


def _explore_specific_drop_details(billing_drop_service, organization, provider, date_range, drop):
    """Show detailed drop information for specific drop."""
    console.print(f"Drop details for '{drop}' in organization '{organization}' provider '{provider}' date range '{date_range}':")

    # Use S3DataService to get drop details (same as list-upload-datasets)
    from src.services.s3_data_service import S3DataService
    s3_service = S3DataService()

    try:
        drop_details = s3_service.get_drop_details(organization, provider, date_range, drop)

        # Display drop summary
        console.print(f"Drop Information:")
        console.print(f"  • Drop ID: {drop_details['drop_id']}")
        console.print(f"  • Active Drop: {'Yes' if drop_details.get('is_active', False) else 'No'}")
        console.print(f"  • File Count: {drop_details['file_count']:,}")
        console.print(f"  • Total Rows: {drop_details['total_rows']:,}")
        console.print()

        # Display file information
        if drop_details['files']:
            console.print(f"Data Files:")

            # Create table for files
            files_table = Table(show_header=True, header_style="bold magenta")
            files_table.add_column("File Name", style="cyan")
            files_table.add_column("Size (MB)", style="yellow", justify="right")
            files_table.add_column("Rows", style="blue", justify="right")
            files_table.add_column("Last Modified", style="green")

            for file_info in drop_details['files']:
                file_size_mb = file_info['size_bytes'] / (1024 * 1024)
                files_table.add_row(
                    file_info['filename'],
                    f"{file_size_mb:.2f}",
                    f"{file_info['rows']:,}" if file_info['rows'] > 0 else "Unknown",
                    file_info['last_modified']
                )

            console.print(files_table)
            console.print()

        # Display column schema if available
        if drop_details.get('columns'):
            console.print(f"Column Schema:")

            # Create table for columns
            columns_table = Table(show_header=True, header_style="bold magenta")
            columns_table.add_column("Column Name", style="cyan")

            for column in drop_details['columns']:
                columns_table.add_row(column)

            console.print(columns_table)

        # Display schema error if any
        if drop_details.get('schema_error'):
            console.print(f"\n[yellow]⚠️  Schema read warning: {drop_details['schema_error']}[/yellow]")

    except Exception as e:
        console.print(f"[yellow]Error getting drop details: {e}[/yellow]")