"""
Command-line interface for uniWeather
"""

import argparse
import asyncio
import sys
from datetime import datetime, timedelta
from .client import uniWeatherCloud


def plot_temperature(args):
    """Plot air temperature from devices"""
    asyncio.run(_plot_temperature_async(args))


async def _plot_temperature_async(args):
    """Async implementation of temperature plotting"""
    # Import plotting libraries
    try:
        import pandas as pd
        import matplotlib
        if not args.show:
            matplotlib.use('Agg')  # Use non-interactive backend if not showing
        import matplotlib.pyplot as plt
    except ImportError:
        print("Error: This command requires pandas and matplotlib")
        print("Install with: pip install pandas matplotlib")
        sys.exit(1)
    
    # Initialize client
    client = uniWeatherCloud(base_url=args.url)
    
    # Connect with API token
    if args.verbose:
        print(f"Connecting to {args.url}...")
    
    try:
        await client.connect(token=args.token)
    except Exception as e:
        print(f"Error: Failed to connect: {e}")
        sys.exit(1)
    
    if args.verbose:
        print("Connected successfully!\n")
    
    # Get devices
    devices = await client.my_devices()
    if not devices:
        devices = await client.my_devices(all=True)
    
    if not devices:
        print("Error: No devices found")
        await client.close()
        sys.exit(1)
    
    if args.verbose:
        print(f"Found {len(devices)} device(s)\n")
    
    # Time range
    end_date = datetime.now()
    start_date = end_date - timedelta(hours=args.hours)
    
    if args.verbose:
        print(f"Querying data from {start_date} to {end_date}\n")
    
    # Collect data from each device
    device_data = []
    for device in devices:
        if args.verbose:
            print(f"Processing device: {device.device_id}")
        
        # Check if device has air_temperature channel
        channels = await client.get_channels(device)
        if 'air_temperature' not in channels:
            if args.verbose:
                print(f"  ⚠ No air_temperature channel available")
            continue
        
        # Query air_temperature channel
        try:
            data = await client.data(
                device=device,
                channels=['air_temperature'],
                from_date=start_date,
                to_date=end_date
            )
            
            df = data.to_dataframe()
            
            if df.empty or 'air_temperature' not in df.columns:
                if args.verbose:
                    print(f"  ⚠ No air_temperature data available")
                continue
            
            valid_points = df['air_temperature'].notna().sum()
            if args.verbose:
                print(f"  ✓ {valid_points} data points")
            
            device_data.append({
                'device_id': device.device_id,
                'df': df
            })
        except Exception as e:
            if args.verbose:
                print(f"  ⚠ Error fetching data: {e}")
            continue
    
    if not device_data:
        print("Error: No devices with air_temperature data found")
        await client.close()
        sys.exit(1)
    
    # Create subplot grid
    n_devices = len(device_data)
    n_cols = 2
    n_rows = (n_devices + 1) // 2
    
    fig, axes = plt.subplots(n_rows, n_cols, figsize=(14, 5 * n_rows))
    fig.suptitle(f'uniWeather - Air Temperature - Last {args.hours} Hours', 
                 fontsize=16, fontweight='bold', y=0.995)
    
    # Flatten axes for easier iteration
    if n_devices == 1:
        axes = [axes]
    else:
        axes = axes.flatten()
    
    # Calculate global min/max for normalized axes across all devices
    global_temp_min = float('inf')
    global_temp_max = float('-inf')
    global_time_min = None
    global_time_max = None
    
    for device_info in device_data:
        df = device_info['df']
        temp_celsius = pd.to_numeric(df['air_temperature'], errors='coerce') - 273.15
        temp_clean = temp_celsius.dropna()
        if len(temp_clean) > 0:
            global_temp_min = min(global_temp_min, temp_clean.min())
            global_temp_max = max(global_temp_max, temp_clean.max())
        
        # Track global time range
        if not df.empty:
            if global_time_min is None or df.index.min() < global_time_min:
                global_time_min = df.index.min()
            if global_time_max is None or df.index.max() > global_time_max:
                global_time_max = df.index.max()
    
    # Auto-determine Y-axis range with appropriate padding
    temp_range = global_temp_max - global_temp_min
    if temp_range < 1:
        padding = 0.5
    else:
        padding = temp_range * 0.1
    
    y_min = global_temp_min - padding
    y_max = global_temp_max + padding
    
    # Plot each device
    for idx, device_info in enumerate(device_data):
        ax = axes[idx]
        df = device_info['df']
        device_id = device_info['device_id']
        
        # Convert Kelvin to Celsius
        temp_celsius = pd.to_numeric(df['air_temperature'], errors='coerce') - 273.15
        temp_clean = temp_celsius.dropna()
        
        if len(temp_clean) > 0:
            temp_min = temp_clean.min()
            temp_mean = temp_clean.mean()
            temp_max = temp_clean.max()
            
            # Plot with filled area
            x_values = temp_celsius.index
            y_values = temp_celsius.values.astype(float)
            ax.plot(x_values, y_values, color='#1f77b4', linewidth=1.5)
            ax.fill_between(x_values, y_values, alpha=0.3, color='#1f77b4')
            
            # Add statistics text box
            stats_text = f"Min: {temp_min:.1f}°C\nMean: {temp_mean:.1f}°C\nMax: {temp_max:.1f}°C"
            ax.text(0.02, 0.98, stats_text, transform=ax.transAxes,
                   verticalalignment='top', bbox=dict(boxstyle='round', 
                   facecolor='wheat', alpha=0.8), fontsize=10)
            
            # Set title with device ID
            ax.set_title(f'Device: {device_id}', fontsize=11, fontweight='bold')
            ax.set_xlabel('Time', fontsize=10)
            ax.set_ylabel('Temperature [°C]', fontsize=10)
            ax.grid(True, alpha=0.3, linestyle='--')
            
            # Set normalized axis limits
            ax.set_xlim(global_time_min, global_time_max)
            ax.set_ylim(y_min, y_max)
            
            # Format x-axis
            ax.tick_params(axis='x', rotation=45)
            fig.autofmt_xdate()
    
    # Hide unused subplots
    for idx in range(n_devices, len(axes)):
        axes[idx].set_visible(False)
    
    plt.tight_layout()
    
    # Save plot
    if args.output:
        plt.savefig(args.output, format=args.format, bbox_inches='tight')
        print(f"\n✓ Plot saved to: {args.output}")
    
    # Show plot if requested
    if args.show:
        plt.show()
    
    # Close connection
    await client.close()
    if args.verbose:
        print("\nConnection closed.")


def list_devices(args):
    """List available devices"""
    asyncio.run(_list_devices_async(args))


async def _list_devices_async(args):
    """Async implementation of device listing"""
    # Initialize client
    client = uniWeatherCloud(base_url=args.url)
    
    # Connect
    try:
        await client.connect(token=args.token)
    except Exception as e:
        print(f"Error: Failed to connect: {e}")
        sys.exit(1)
    
    # Get devices
    devices = await client.my_devices()
    if not devices:
        devices = await client.my_devices(all=True)
    
    if not devices:
        print("No devices found")
        await client.close()
        return
    
    print(f"\nFound {len(devices)} device(s):\n")
    
    for idx, device in enumerate(devices, 1):
        print(f"{idx}. Device ID: {device.device_id}")
        
        if args.verbose:
            try:
                channels = await client.get_channels(device)
                print(f"   Channels ({len(channels)}): {', '.join(channels)}")
            except Exception as e:
                print(f"   Error fetching channels: {e}")
        
        print()
    
    await client.close()


def download_csv(args):
    """Download device data as CSV"""
    asyncio.run(_download_csv_async(args))


async def _download_csv_async(args):
    """Async implementation of CSV download"""
    # Initialize client
    client = uniWeatherCloud(base_url=args.url)
    
    # Connect
    if args.verbose:
        print(f"Connecting to {args.url}...")
    
    try:
        await client.connect(token=args.token)
    except Exception as e:
        print(f"Error: Failed to connect: {e}")
        sys.exit(1)
    
    if args.verbose:
        print("Connected successfully!\n")
    
    # Time range
    from datetime import datetime, timedelta
    end_date = datetime.now()
    start_date = end_date - timedelta(hours=args.hours)
    
    # Parse channels
    channels = None if args.channels == "all" else args.channels.split(',')
    
    if args.verbose:
        print(f"Device: {args.device}")
        print(f"Channels: {args.channels}")
        print(f"Time range: {start_date} to {end_date}")
        print(f"Downloading...\n")
    
    # Download CSV
    try:
        await client.download_csv(
            device=args.device,
            filename=args.output,
            channels=channels,
            from_date=start_date,
            to_date=end_date
        )
        print(f"✓ Data saved to: {args.output}")
    except Exception as e:
        print(f"Error: Failed to download data: {e}")
        await client.close()
        sys.exit(1)
    
    await client.close()
    if args.verbose:
        print("\nConnection closed.")


def main():
    """Main CLI entry point"""
    parser = argparse.ArgumentParser(
        description='uniWeather - IoT weather station data analysis tools',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # List all devices
  uniweather list --token YOUR_API_KEY
  
  # List devices with channels
  uniweather list --token YOUR_API_KEY --verbose
  
  # Download CSV data for a device
  uniweather download --token YOUR_API_KEY --device DEVICE_ID --output data.csv
  
  # Download specific channels
  uniweather download -t TOKEN -d DEVICE_ID -o data.csv --channels "air_temperature,humidity"
  
  # Plot temperature for last 24 hours
  uniweather plot-temp --token YOUR_API_KEY --output temp.pdf
  
  # Plot last 48 hours with verbose output
  uniweather plot-temp --token YOUR_API_KEY --hours 48 --output temp.pdf --verbose

Environment Variables:
  UNIWEATHER_TOKEN    API token (alternative to --token)
  UNIWEATHER_URL      API base URL (default: https://api.uniweather.io)
        """
    )
    
    subparsers = parser.add_subparsers(dest='command', help='Available commands')
    
    # list command
    list_parser = subparsers.add_parser('list', help='List available devices')
    list_parser.add_argument('--token', '-t',
                            help='API authentication token (or use UNIWEATHER_TOKEN env var)')
    list_parser.add_argument('--url', '-u',
                            default='https://api.uniweather.io',
                            help='API base URL (default: https://api.uniweather.io)')
    list_parser.add_argument('--verbose', '-v',
                            action='store_true',
                            help='Show channels for each device')
    
    # download command
    download_parser = subparsers.add_parser('download', help='Download device data as CSV')
    download_parser.add_argument('--token', '-t',
                                help='API authentication token (or use UNIWEATHER_TOKEN env var)')
    download_parser.add_argument('--url', '-u',
                                default='https://api.uniweather.io',
                                help='API base URL (default: https://api.uniweather.io)')
    download_parser.add_argument('--device', '-d',
                                required=True,
                                help='Device ID to download data from')
    download_parser.add_argument('--output', '-o',
                                required=True,
                                help='Output CSV file path')
    download_parser.add_argument('--channels', '-c',
                                default='all',
                                help='Channels to download (comma-separated or "all", default: all)')
    download_parser.add_argument('--hours',
                                type=int, default=24,
                                help='Number of hours to query (default: 24)')
    download_parser.add_argument('--verbose', '-v',
                                action='store_true',
                                help='Verbose output')
    
    # plot-temp command
    plot_parser = subparsers.add_parser('plot-temp', help='Plot air temperature from devices')
    plot_parser.add_argument('--token', '-t', 
                            help='API authentication token (or use UNIWEATHER_TOKEN env var)')
    plot_parser.add_argument('--url', '-u', 
                            default='https://api.uniweather.io',
                            help='API base URL (default: https://api.uniweather.io)')
    plot_parser.add_argument('--hours', 
                            type=int, default=24,
                            help='Number of hours to query (default: 24)')
    plot_parser.add_argument('--output', '-o',
                            help='Output file path (e.g., temp.pdf)')
    plot_parser.add_argument('--format', '-f',
                            choices=['pdf', 'png', 'svg'],
                            default='pdf',
                            help='Output format (default: pdf)')
    plot_parser.add_argument('--show', '-s',
                            action='store_true',
                            help='Show plot interactively')
    plot_parser.add_argument('--verbose', '-v',
                            action='store_true',
                            help='Verbose output')
    
    args = parser.parse_args()
    
    # Check if command was provided
    if not args.command:
        parser.print_help()
        sys.exit(1)
    
    # Get token from env if not provided
    if not args.token:
        import os
        args.token = os.environ.get('UNIWEATHER_TOKEN')
        if not args.token:
            print("Error: API token required. Provide via --token or UNIWEATHER_TOKEN env var")
            sys.exit(1)
    
    # Route to appropriate command handler
    if args.command == 'list':
        list_devices(args)
    elif args.command == 'download':
        download_csv(args)
    elif args.command == 'plot-temp':
        # Require output or show for plot-temp
        if not args.output and not args.show:
            print("Error: Must specify --output FILE or --show")
            sys.exit(1)
        plot_temperature(args)


if __name__ == '__main__':
    main()

