import re
import shutil
from pathlib import Path
from typing import List, Optional

import polars as pl
import typer
from rich.console import Console
from rich.table import Table

# Legacy reference/usage-reference imports removed - replaced by unified data commands
from src.cli.analysis import app as analysis_app
from src.cli.core.upload import app as upload_app
from src.cli.data import app as data_app
# Temporarily disabled due to legacy pipeline dependencies
# from cli.pipeline import app as pipeline_app
from src.cli.profiles import app as profiles_app
# from cli.telemetry import app as telemetry_app  # Temporarily disabled
from src.exploration import exploration
from src.generate.cli.generate_cli import app as generate_app
from src.k8s.cli.k8s_cli import k8s_app
from src.metadata.cli.metadata_cli import metadata_app
from src.usage.cli.usage_cli import usage_app
from src.discount.cli.discount_cli import discount_app
from src.services.s3_data_service import S3DataService

app = typer.Typer(help="CloudZero Billing Generator CLI")
# Temporarily disabled due to legacy pipeline dependencies
# app.add_typer(pipeline_app, name="pipeline")
# app.add_typer(telemetry_app, name="telemetry")  # Temporarily disabled
app.add_typer(profiles_app, name="profiles")
app.add_typer(analysis_app, name="analyze")
app.add_typer(data_app, name="data")
app.add_typer(upload_app, name="upload")
app.add_typer(generate_app, name="generate")
app.add_typer(k8s_app, name="k8s")
app.add_typer(metadata_app, name="metadata")
app.add_typer(usage_app, name="usage")
app.add_typer(discount_app, name="discount")
# Legacy reference/usage-reference commands removed - replaced by unified data commands

# Note: upload_app now uses S3-based approach (no workspace validation needed)

console = Console()

DEFAULT_CONFIG_YAML = """# config.yaml

org_name: {org}
api_token: ${{CLOUDBILLGEN_{env_suffix}_API_TOKEN}}
# api_url: https://api.demo.cloudzero.com/v1/ingest
connections:
  AWS:
    - your-aws-connection-id-here
  GCP:
    - your-gcp-connection-id-here
  Azure:
    - your-azure-connection-id-here

# Upload Configuration
upload:
  # Generated data upload settings
  generated:
    # Explicit data source selection
    data_source:
      run: "latest" # "latest" or specific run ID like "20241201_143022"
      stage: "generate" # Stage to upload (generate, validate, etc.)

    # Upload behavior settings (enforced maximums)
    settings:
      concurrency: 6 # Max: 20, Min: 1
      max_retries: 5 # Max: 10, Min: 1
      timeout: 60.0 # Max: 300.0, Min: 10.0
      dry_run: true
      resume: false

  # Ad-hoc CSV upload settings (FIXED VALUES - user changes ignored)
  adhoc:
    # These values are ENFORCED regardless of user changes
    input_dir: "adhoc/input" # FIXED: always adhoc/input/
    mapping_file: "adhoc/mapping.csv" # FIXED: always adhoc/mapping.csv
    output_dir: "adhoc/output" # FIXED: always adhoc/output/
    concurrency: 4 # FIXED: always 4
    max_retries: 3 # FIXED: always 3
    timeout: 30.0 # FIXED: always 30.0
    dry_run: false # FIXED: always false
"""

DEFAULT_PIPELINE_YAML = """# pipeline.jobs.yaml

stages:
  generate:
    - reference_data: data/reference.csv
      start_date: 2025-04-01
      end_date: 2025-04-30
      total_cost: 1234.56
      resource_count: 100
      filters:
        - cloud_provider: [AWS]
          variance_profile: "business_hours_daily"  # Realistic business hours variance patterns
          anomaly_profile: "quarterly_cost_optimization"  # Quarterly cost optimization cycles
          service: [EC2]
      

    - reference_data: data/reference.csv
      start_date: 2025-04-01
      end_date: 2025-04-30
      total_cost: 5678.90
      resource_count: 200
      filters:
        - cloud_provider: [GCP]
          variance_profile: "analytics_workload"  # Analytics burst processing patterns
          # No anomaly profile for this job - demonstrates mixed configuration
          service: [BigQuery]

  # Simplified metadata allocation
  metadata:
    majority_region: "us-east-1"        # 70% allocation to us-east-1
    majority_environment: "production"  # 70% allocation to production
    base_allocation: "products"         # Use products profile for allocation

  # Usage pricing calculation (auto-executes when --stage usage is run)
  usage:
    # No execution control flags - command-driven only
"""


DEFAULT_ENV = """# .env - Add your CloudZero API token here
# Get your API token from: https://app.cloudzero.com/organization/api-keys

CLOUDBILLGEN_{env_suffix}_API_TOKEN=your-cloudzero-api-token-here
"""


@app.command()
def init(
    force: bool = typer.Option(False, help="Overwrite existing files if they exist"),
):
    """Initialize ~/.czbillgen workspace with default structure and templates."""
    workspace_dir = Path.home() / ".czbillgen"
    
    # Create main directories
    workspace_dir.mkdir(exist_ok=True)
    (workspace_dir / "logs").mkdir(exist_ok=True)
    (workspace_dir / "configs").mkdir(exist_ok=True)
    (workspace_dir / "configs" / "generate").mkdir(exist_ok=True)
    (workspace_dir / "configs" / "upload").mkdir(exist_ok=True)
    
    # Template paths
    env_template_path = workspace_dir / ".env.template"
    generate_template_path = workspace_dir / "configs" / "generate" / "example-config.yaml"
    upload_template_path = workspace_dir / "configs" / "upload" / "upload.template.yaml"
    
    # Check if templates already exist (only warn, don't exit unless force is needed)
    templates_exist = env_template_path.exists()
    if templates_exist and not force:
        typer.echo(f"✔ Workspace already exists: {workspace_dir}")
        typer.echo("  Use --force to recreate template files")
        return
    
    # Create .env.template
    env_template_content = """# CloudZero API Tokens for All Organizations
# Copy this file to .env and add your actual tokens

# Example org tokens (replace with your actual org names and tokens):
# CLOUDZERO_ACME_CORP_API_TOKEN=your-acme-token-here
# CLOUDZERO_BETA_COMPANY_API_TOKEN=your-beta-token-here
# CLOUDZERO_DEMO_ORG_API_TOKEN=your-demo-token-here

# Get your tokens from: https://app.cloudzero.com/organization/api-keys

# S3 Configuration for Reference Data and Dataset Storage
# AWS credentials are handled automatically via boto3 default credential chain
# Supports: AWS SSO (aws sso login), environment variables, IAM roles, etc.
# No need to configure AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY in .env
AWS_DEFAULT_REGION=us-east-1
# AWS_PROFILE=your-aws-profile-name  # Optional: specify AWS profile for SSO

# S3 Bucket and Paths
CZBILLGEN_S3_BUCKET=your-czbillgen-bucket-name
CZBILLGEN_S3_REFERENCE_PATH=czbillgen/reference_data

# Generation Performance Settings
CZBILLGEN_ACCUMULATION_MEMORY_MB=500  # Memory limit for data accumulation before upload (MB)
CZBILLGEN_MEMORY_LOG_LEVEL=INFO       # Memory logging level: DEBUG, INFO, WARN, ERROR
"""
    
    # Create generate template
    generate_template_content = """# CloudZero Billing Generator - Generation Configuration
# This file defines how to generate synthetic billing data using shape-based profiles

generation_jobs:
  # AWS workload example
  - name: "aws-compute-workload"
    reference_data: "data/reference.parquet"  # Path to reference data file
    start_date: "2024-01-01"
    end_date: "2024-12-31"
    total_cost: 50000.00  # Total cost to distribute across the time period
    resource_count: 25    # Number of resources to generate per service
    
    filters:
      - cloud_provider: AWS
        variance_profile: "linear_growth"      # Shape-based profile name
        anomaly_profile: "exponential_burst"   # Shape-based profile name
        
        services:
          - name: AmazonEC2
            usage_families:
              - name: "Compute Instance"
                resource_types:
                  - name: "instance"
                    operations:
                      - name: "RunInstances"
                        usage_types:
                          - "BoxUsage:c5.large"
                          - "BoxUsage:c5.xlarge"
                          - "BoxUsage:c5.2xlarge"
              
              - name: "Data Transfer"
                resource_types:
                  - name: "data-transfer"
                    operations:
                      - name: "InterZone-Out"
                        usage_types: []  # Empty means wildcard (match all)
          
          - name: AmazonS3
            usage_families:
              - name: "Storage"
                resource_types:
                  - name: "bucket"
                    operations:
                      - name: "StandardStorage"
                        usage_types: []

  # GCP workload example
  - name: "gcp-analytics-workload"
    reference_data: "data/reference.parquet"
    start_date: "2024-01-01"
    end_date: "2024-12-31"
    total_cost: 30000.00
    resource_count: 15
    
    filters:
      - cloud_provider: GCP
        variance_profile: "burst_cycles"        # Analytics workload pattern
        anomaly_profile: "scaling_ramp"         # Infrastructure scaling pattern
        
        services:
          - name: "Compute Engine"
            usage_families:
              - name: "N1 Predefined Instance Core running in Americas"
                resource_types: []  # Empty means wildcard
          
          - name: "Cloud SQL"
            usage_families:
              - name: "Cloud SQL for MySQL: Zonal - Standard storage in Americas"
                resource_types: []

  # Azure workload example  
  - name: "azure-stable-workload"
    reference_data: "data/reference.parquet"
    start_date: "2024-01-01"
    end_date: "2024-12-31"
    total_cost: 20000.00
    resource_count: 10
    
    filters:
      - cloud_provider: Azure
        variance_profile: "seasonal_peaks"      # Seasonal usage pattern
        # No anomaly profile - demonstrates mixed configuration
        
        services:
          - name: "microsoft.compute"
            usage_families: []  # Empty means wildcard (match all)
          
          - name: "microsoft.storage"
            usage_families: []

# Available Shape-Based Profile Names:
#
# Variance Profiles (cost variation patterns):
#   - linear_growth: Gradual, steady cost increases over time
#   - burst_cycles: Periodic bursts of high usage (analytics workloads)
#   - seasonal_peaks: Seasonal usage patterns (holidays, quarters)
#   - periodic_surge: Regular periodic cost surges
#   - weekend_heavy: Higher usage on weekends
#
# Anomaly Profiles (unusual cost events):
#   - exponential_burst: Sudden exponential cost increases
#   - scaling_ramp: Infrastructure scaling events
#   - deadline_rush: End-of-period cost rushes
#   - sudden_drop: Immediate cost drops
#   - spike_event: Brief extreme cost events

# Notes:
# - Empty arrays [] act as wildcards (match all available options)
# - Reference data should contain the cloud services you want to generate
# - total_cost is distributed across all resources and time period
# - Variance and anomaly profiles can be mixed and matched
# - Use `czbillgen generate validate` to check your configuration
"""
    
    # Create upload.template.yaml
    upload_template_content = """# Upload Configuration Template
# Copy this file to upload.yaml and customize for your needs

# Dataset to upload (stored in S3)
dataset: "demo-2024-q1"

# Which months to upload from the dataset
months:
  - "2024-01"
  - "2024-02" 
  - "2024-03"

# Organizations to upload to
organizations:
  - name: "acme-corp"
    api_token_env: "CLOUDZERO_ACME_CORP_API_TOKEN"
    connections:
      AWS:
        - "aws-connection-id-1"
        - "aws-connection-id-2"
      GCP:
        - "gcp-connection-id-1" 
      Azure:
        - "azure-connection-id-1"
        
  - name: "beta-company"
    api_token_env: "CLOUDZERO_BETA_COMPANY_API_TOKEN"
    connections:
      AWS:
        - "aws-connection-id-3"
      GCP: []
      Azure: []

# Upload settings
settings:
  concurrency: 6
  max_retries: 3
  timeout: 60.0
  dry_run: false
"""
    
    # Write template files
    env_template_path.write_text(env_template_content)
    generate_template_path.write_text(generate_template_content)
    upload_template_path.write_text(upload_template_content)
    
    action = "Recreated" if templates_exist else "Initialized"
    typer.echo(f"✔ {action} workspace: {workspace_dir}")
    typer.echo(f"✔ Template: {env_template_path}")
    typer.echo(f"✔ Template: {generate_template_path}")
    typer.echo(f"✔ Template: {upload_template_path}")
    typer.echo(f"✔ Directory: {workspace_dir / 'configs' / 'generate'}/")
    typer.echo(f"✔ Directory: {workspace_dir / 'configs' / 'upload'}/")
    typer.echo(f"✔ Directory: {workspace_dir / 'logs'}/")
    typer.echo("")
    typer.echo("📋 Next steps:")
    typer.echo(f"  1. Copy template files:")
    typer.echo(f"     cp {env_template_path} {workspace_dir}/.env")
    typer.echo(f"     cp {upload_template_path} {workspace_dir}/configs/upload/upload.yaml")
    typer.echo(f"  2. Edit {workspace_dir}/.env with your actual API tokens")
    typer.echo(f"  3. Create generate configs in {workspace_dir}/configs/generate/")
    typer.echo(f"  4. Create upload configs in {workspace_dir}/configs/upload/")
    typer.echo("  5. Generate datasets: czbillgen generate run --config-path ~/.czbillgen/configs/generate/")
    typer.echo("  6. Upload to organizations: czbillgen upload --config ~/.czbillgen/configs/upload/upload.yaml")
    typer.echo("")
    typer.echo("🔗 Get API tokens: https://app.cloudzero.com/organization/api-keys")


def format_cost_columns(df: pl.DataFrame, cols: List[str]) -> pl.DataFrame:
    return df.with_columns(
        [
            pl.col(col)
            .round(2)
            .map_elements(lambda x: f"{x:,.2f}", return_dtype=pl.Utf8)
            .alias(f"{col}_formatted")
            for col in cols
        ]
    )


def format_count_columns(df: pl.DataFrame, cols: List[str]) -> pl.DataFrame:
    return df.with_columns(
        [
            pl.col(col)
            .map_elements(lambda x: f"{x:,.2f}", return_dtype=pl.Utf8)
            .alias(f"{col}_formatted")
            for col in cols
        ]
    )


@app.command()
def summarize(
    org: str = typer.Option(
        ..., "--org", help="Name of the org to summarize output for"
    ),
    run: Optional[str] = typer.Option(
        None, "--run", help="Timestamp of a specific run to analyze"
    ),
    provider: Optional[str] = typer.Option(
        None, "--provider", help="Filter summary to a specific cloud provider"
    ),
    notebook: bool = typer.Option(
        False,
        "--notebook",
        help="Generate Jupyter notebook template for deeper analysis",
    ),
):
    runs_dir = Path(f"cloudzero-demo-billing/orgs/{org}/billing/runs")
    if not runs_dir.exists():
        console.print(f"[red]No runs found at {runs_dir}[/red]")
        raise typer.Exit(1)

    valid_runs = sorted(runs_dir.glob("*"), key=lambda p: p.name)
    valid_run_names = [p.name for p in valid_runs if p.is_dir()]

    if run:
        if not re.match(r"^\d{4}-\d{2}-\d{2}_\d{6}$", run):
            console.print(
                "[red]Invalid --run format. Expected: YYYY-MM-DD_HHMMSS[/red]"
            )
            raise typer.Exit(1)

        if run not in valid_run_names:
            console.print(f"[red]Run folder not found: {run}[/red]")
            if valid_run_names:
                console.print(
                    "[bold]Available runs:[/bold] " + ", ".join(valid_run_names)
                )
            else:
                console.print("[yellow]No valid run folders found yet.[/yellow]")
            raise typer.Exit(1)
        run_dir = runs_dir / run
    else:
        if not valid_run_names:
            console.print(f"[red]No valid run folders found in {runs_dir}[/red]")
            raise typer.Exit(1)
        run_dir = runs_dir / valid_run_names[-1]  # Most recent by name

    # New: Look for partitioned files under generate/
    generate_dir = run_dir / "generate"
    parquet_files = list(generate_dir.rglob("*.parquet"))
    if not parquet_files:
        console.print(f"[red]No Parquet files found in {generate_dir}[/red]")
        raise typer.Exit(1)

    console.print(f"[dim]Reading {len(parquet_files)} files from {generate_dir}[/dim]")
    df = pl.concat([pl.read_parquet(pf) for pf in parquet_files])

    if provider:
        df = df.filter(pl.col("cloud_provider") == provider)
        if df.is_empty():
            console.print(
                f"[yellow]No rows found for provider '{provider}' in run {run_dir.name}[/yellow]"
            )
            raise typer.Exit(0)

    pl.Config.set_tbl_rows(100)

    console.rule("[bold cyan]Cost Overview")
    console.print(f"\n[bold green]Summarizing run:[/bold green] {run_dir.name}")
    if provider:
        console.print(f"[bold green]Filtered to provider:[/bold green] {provider}")

    console.print(f"[bold]Total Cost:[/bold] ${exploration.get_total_cost(df):,.2f}")

    console.print("\n[bold]Cost by Provider:[/bold]")
    formatted = format_cost_columns(
        exploration.get_cost_by_provider(df), cols=["total_cost"]
    )
    console.print(formatted.select(["cloud_provider", "total_cost_formatted"]))

    console.print("\n[bold]Cost by Month:[/bold]")
    formatted_monthly = format_cost_columns(
        exploration.get_cost_by_month(df), cols=["total_cost"]
    )
    console.print(
        formatted_monthly.sort("month").select(["month", "total_cost_formatted"])
    )

    console.print("\n[bold]Cost by Provider and Month:[/bold]")
    formatted_provider_month = format_cost_columns(
        exploration.get_min_max_cost_month_by_provider(df),
        cols=["min_total_cost", "max_total_cost"],
    )
    console.print(
        formatted_provider_month.sort(["cloud_provider", "min_month"]).select(
            [
                "cloud_provider",
                "min_month",
                "min_total_cost_formatted",
                "max_month",
                "max_total_cost_formatted",
            ]
        )
    )

    console.rule("[bold cyan]Line Item & Upload Estimates")
    line_items = exploration.get_min_max_line_items_month_by_provider(df)
    line_items = format_count_columns(
        line_items, cols=["min_line_items", "max_line_items"]
    )
    line_items = line_items.select(
        [
            "cloud_provider",
            "min_month",
            "min_line_items_formatted",
            "max_month",
            "max_line_items_formatted",
        ]
    )
    console.print("\n[bold]Line Items by Provider and Month:[/bold]")
    console.print(line_items)

    payloads = exploration.get_peak_payload_month_by_provider(df)
    payloads = format_count_columns(
        payloads, cols=["line_items", "estimated_mb", "estimated_payloads"]
    )
    payloads = payloads.select(
        [
            "cloud_provider",
            "month",
            "line_items_formatted",
            "estimated_mb_formatted",
            "estimated_payloads_formatted",
            "required_connections",
        ]
    )
    console.print("\n[bold]Estimated Payloads and Connections:[/bold]")
    console.print(payloads)

    console.rule("[bold cyan]Data Quality Checks")
    nulls = exploration.get_null_counts(df)
    total_nulls = sum(nulls.values())
    console.print(f"[bold]Total Nulls:[/bold] {total_nulls}")
    for col, count in nulls.items():
        if count:
            console.print(f"  - {col}: {count}")

    bad_resources = exploration.get_service_usage_resources(df)
    console.print(
        f"\n[bold]Unique 'service-usage' resource_type entries:[/bold] {bad_resources.shape[0]}"
    )

    if notebook:
        console.print(
            "\n[bold green]Notebook generation is not yet implemented.[/bold green]"
        )


@app.command("list-datasets")
def list_datasets(
    dataset: Optional[str] = typer.Option(None, "--dataset", help="Dataset name to drill down into"),
    stage: Optional[str] = typer.Option(None, "--stage", help="Stage name to drill down into"),
    provider: Optional[str] = typer.Option(None, "--provider", help="Provider name to drill down into"),
    month: Optional[str] = typer.Option(None, "--month", help="Month to show column schema for (e.g., '2024-07')"),
):
    """
    List datasets with progressive drill-down capabilities.
    
    Usage:
      czbillgen list-datasets                                    # List all datasets
      czbillgen list-datasets --dataset 2025-01-15_14-30-22     # List stages for dataset
      czbillgen list-datasets --dataset NAME --stage generate   # List providers for dataset+stage
      czbillgen list-datasets --dataset NAME --stage generate --provider AWS  # List months for dataset+stage+provider
      czbillgen list-datasets --dataset NAME --stage generate --provider AWS --month 2024-07  # Show column schema for specific month
    """
    console = Console()
    
    try:
        s3_service = S3DataService()
        
        # Level 1: List all datasets
        if not dataset:
            datasets = s3_service.list_datasets()
            if not datasets:
                console.print("[yellow]No datasets found[/yellow]")
                return
            
            console.print(f"[bold]Available datasets:[/bold]")
            for dataset_name in datasets:
                console.print(f"  • {dataset_name}")
            
            console.print(f"\n[dim]Use --dataset to drill down into a specific dataset[/dim]")
            return
        
        # Level 2: List stages for dataset
        if not stage:
            stages = s3_service.list_stages(dataset)
            if not stages:
                console.print(f"[yellow]No stages found for dataset '{dataset}'[/yellow]")
                return
            
            console.print(f"[bold]Stages for dataset '{dataset}':[/bold]")
            for stage_name in stages:
                console.print(f"  • {stage_name}")
            
            console.print(f"\n[dim]Use --stage to drill down into a specific stage[/dim]")
            return
        
        # Level 3: List providers for dataset+stage
        if not provider:
            providers = s3_service.list_providers(dataset, stage)
            if not providers:
                console.print(f"[yellow]No providers found for dataset '{dataset}' stage '{stage}'[/yellow]")
                return
            
            console.print(f"[bold]Providers for dataset '{dataset}' stage '{stage}':[/bold]")
            for provider_name in providers:
                console.print(f"  • {provider_name}")
            
            console.print(f"\n[dim]Use --provider to drill down into a specific provider[/dim]")
            return
        
        # Level 4: List months for dataset+stage+provider
        if not month:
            months_with_counts = s3_service.list_months_with_counts(dataset, stage, provider)
            if not months_with_counts:
                console.print(f"[yellow]No months found for dataset '{dataset}' stage '{stage}' provider '{provider}'[/yellow]")
                return
            
            console.print(f"[bold]Months for dataset '{dataset}' stage '{stage}' provider '{provider}':[/bold]")
            
            # Create table for months with line item counts
            table = Table(show_header=True, header_style="bold magenta")
            table.add_column("Month", style="cyan")
            table.add_column("Line Items", style="green", justify="right")
            
            for month_name, line_count in months_with_counts:
                table.add_row(month_name, f"{line_count:,}" if line_count > 0 else "Unknown")
            
            console.print(table)
            console.print(f"\n[dim]Use --month to view column schema for a specific month[/dim]")
            return
        
        # Level 5: Show column schema for specific month
        try:
            schema_info = s3_service.get_month_schema(dataset, stage, provider, month)
            
            console.print(f"[bold]Schema for dataset '{dataset}' stage '{stage}' provider '{provider}' month '{month}':[/bold]")
            console.print(f"[bold]Row count:[/bold] {schema_info['row_count']:,}")
            console.print()
            
            # Create table for column schema
            schema_table = Table(show_header=True, header_style="bold magenta")
            schema_table.add_column("Column Name", style="cyan")
            schema_table.add_column("Data Type", style="green")
            
            for column in schema_info['columns']:
                data_type = schema_info['dtypes'][column]
                schema_table.add_row(column, data_type)
            
            console.print(schema_table)
            
        except ValueError as e:
            console.print(f"[red]❌ {e}[/red]")
            return
        
    except ValueError as e:
        console.print(f"[red]❌ {e}[/red]")
        raise typer.Exit(1)
    except Exception as e:
        console.print(f"[red]❌ Failed to list datasets: {e}[/red]")
        raise typer.Exit(1)


@app.command("list-upload-datasets")
def list_upload_datasets(
    org: Optional[str] = typer.Option(None, "--org", help="Organization name to drill down into"),
    provider: Optional[str] = typer.Option(None, "--provider", help="Provider name to drill down into"),
    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"),
):
    """
    List upload-ready datasets with progressive drill-down capabilities.
    
    Usage:
      czbillgen list-upload-datasets                                          # List all organizations
      czbillgen list-upload-datasets --org DemoTest                          # List providers for organization  
      czbillgen list-upload-datasets --org DemoTest --provider AWS           # List date ranges for org+provider
      czbillgen list-upload-datasets --org DemoTest --provider AWS --date-range 20240701-20240801  # Show drops table
      czbillgen list-upload-datasets --org DemoTest --provider AWS --date-range 20240701-20240801 --drop 20250722T210122Z  # Show drop details
    """
    console = Console()
    
    try:
        s3_service = S3DataService()
        
        # Level 1: List all organizations
        if not org:
            organizations = s3_service.list_upload_organizations()
            if not organizations:
                console.print("[yellow]No organizations found in upload-ready datasets[/yellow]")
                return
            
            console.print(f"[bold]Available organizations in upload-ready datasets:[/bold]")
            for org_name in organizations:
                console.print(f"  • {org_name}")
            
            console.print(f"\n[dim]Use --org to drill down into a specific organization[/dim]")
            return
        
        # Level 2: List providers for organization
        if not provider:
            providers = s3_service.list_upload_providers(org)
            if not providers:
                console.print(f"[yellow]No providers found for organization '{org}' in upload-ready datasets[/yellow]")
                return
            
            console.print(f"[bold]Providers for organization '{org}' in upload-ready datasets:[/bold]")
            for provider_name in providers:
                console.print(f"  • {provider_name}")
            
            console.print(f"\n[dim]Use --provider to drill down into a specific provider[/dim]")
            return
        
        # Level 3: List date ranges for organization + provider
        if not date_range:
            date_ranges = s3_service.list_upload_date_ranges(org, provider)
            if not date_ranges:
                console.print(f"[yellow]No date ranges found for organization '{org}' provider '{provider}' in upload-ready datasets[/yellow]")
                return
            
            console.print(f"[bold]Date ranges for organization '{org}' provider '{provider}' in upload-ready datasets:[/bold]")
            
            # Create table for date ranges
            table = Table(show_header=True, header_style="bold magenta")
            table.add_column("Date Range", style="cyan")
            table.add_column("Period", style="green")
            
            for date_range_name in date_ranges:
                # Parse date range to show readable period
                try:
                    start_date = date_range_name.split('-')[0]
                    end_date = date_range_name.split('-')[1]
                    # Format as YYYY-MM-DD for readability
                    start_formatted = f"{start_date[:4]}-{start_date[4:6]}-{start_date[6:8]}"
                    end_formatted = f"{end_date[:4]}-{end_date[4:6]}-{end_date[6:8]}"
                    period = f"{start_formatted} to {end_formatted}"
                except:
                    period = "Invalid format"
                
                table.add_row(date_range_name, period)
            
            console.print(table)
            console.print(f"\n[dim]Use --date-range to view manifest and data info for a specific date range[/dim]")
            return
        
        # Level 4: Show drops table for specific date range
        if not drop:
            try:
                drops_info = s3_service.list_drops_in_date_range(org, provider, date_range)
                
                if not drops_info:
                    console.print(f"[yellow]No drops found for organization '{org}' provider '{provider}' date range '{date_range}'[/yellow]")
                    return
                
                console.print(f"[bold]Drops for organization '{org}' provider '{provider}' date range '{date_range}':[/bold]")
                
                # Create table for drops
                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")
                
                # 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"]
                    
                    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"
                    )
                
                console.print(table)
                console.print(f"\n[dim]Use --drop to view detailed file information for a specific drop[/dim]")
                return
                
            except ValueError as e:
                console.print(f"[red]❌ {e}[/red]")
                return
        
        # Level 5: Show detailed drop information
        try:
            drop_details = s3_service.get_drop_details(org, provider, date_range, drop)
            
            console.print(f"[bold]Drop details for '{drop}' in organization '{org}' provider '{provider}' date range '{date_range}':[/bold]")
            
            # Display drop summary
            console.print(f"[bold]Drop Information:[/bold]")
            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"[bold]Data Files:[/bold]")
                
                # 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"[bold]Column Schema:[/bold]")
                
                # 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 ValueError as e:
            console.print(f"[red]❌ {e}[/red]")
            return
        
    except ValueError as e:
        console.print(f"[red]❌ {e}[/red]")
        raise typer.Exit(1)
    except Exception as e:
        console.print(f"[red]❌ Failed to list upload datasets: {e}[/red]")
        raise typer.Exit(1)


if __name__ == "__main__":
    app()
