"""
CLI commands for querying health data.

Provides command-line interface for viewing and analyzing health metrics.
"""

import sys
from datetime import date, datetime, timedelta
from pathlib import Path
from typing import Optional, List, Union

import click

# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from health import config
from health.services.query import HealthDataQuery
from health.utils.logging_config import setup_logger

logger = setup_logger(__name__)


def format_date(date_obj: date) -> str:
    """Format date for display.

    Args:
        date_obj: Date to format

    Returns:
        Formatted date string
    """
    return date_obj.strftime("%Y-%m-%d (%A)")


def format_seconds_to_hms(seconds: Optional[Union[int, float]]) -> str:
    """Convert seconds to HH:MM:SS format.

    Args:
        seconds: Number of seconds (int or float)

    Returns:
        Formatted time string
    """
    if seconds is None:
        return "N/A"

    # Convert to int if it's a float
    seconds = int(seconds)

    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    secs = seconds % 60

    return f"{hours:02d}:{minutes:02d}:{secs:02d}"


def format_number(value: Optional[Union[int, float]], decimals: int = 0) -> str:
    """Safely format a number with thousand separators.

    Args:
        value: Number to format
        decimals: Number of decimal places

    Returns:
        Formatted number string or 'N/A'
    """
    if value is None:
        return "N/A"

    if decimals > 0:
        return f"{value:,.{decimals}f}"
    else:
        return f"{int(value):,}"


def print_daily_summary(summary: dict) -> None:
    """Print a formatted daily summary.

    Args:
        summary: Daily summary dictionary
    """
    target_date = datetime.fromisoformat(summary["date"]).date()

    print(f"\n{'='*80}")
    print(f"📊 Health Data Summary for {format_date(target_date)}")
    print(f"{'='*80}\n")

    metrics = summary.get("metrics", {})

    # Steps
    if "steps" in metrics:
        steps = metrics["steps"]
        print(f"🚶 Steps:")
        print(f"   Total Steps: {format_number(steps.get('total_steps'))}")
        if steps.get('total_distance_meters'):
            print(f"   Distance: {steps.get('total_distance_meters', 0) / 1000:.2f} km")
        if steps.get('calories_burned'):
            print(f"   Calories: {format_number(steps.get('calories_burned'))} kcal")
        print()

    # Sleep
    if "sleep" in metrics:
        sleep = metrics["sleep"]
        print(f"😴 Sleep:")
        if sleep.get('total_sleep_seconds'):
            print(f"   Total Sleep: {format_seconds_to_hms(sleep.get('total_sleep_seconds'))}")
        if sleep.get('deep_sleep_seconds'):
            print(f"   Deep Sleep: {format_seconds_to_hms(sleep.get('deep_sleep_seconds'))}")
        if sleep.get('light_sleep_seconds'):
            print(f"   Light Sleep: {format_seconds_to_hms(sleep.get('light_sleep_seconds'))}")
        if sleep.get('rem_sleep_seconds'):
            print(f"   REM Sleep: {format_seconds_to_hms(sleep.get('rem_sleep_seconds'))}")
        if sleep.get('sleep_score') is not None:
            print(f"   Sleep Score: {sleep.get('sleep_score')}/100")
        print()

    # Heart Rate
    if "heart_rate" in metrics:
        hr = metrics["heart_rate"]
        print(f"💓 Heart Rate:")
        if hr.get('resting_heart_rate'):
            print(f"   Resting HR: {hr.get('resting_heart_rate')} bpm")
        if hr.get('min_heart_rate'):
            print(f"   Min HR: {hr.get('min_heart_rate')} bpm")
        if hr.get('max_heart_rate'):
            print(f"   Max HR: {hr.get('max_heart_rate')} bpm")
        if hr.get('average_heart_rate'):
            print(f"   Average HR: {hr.get('average_heart_rate')} bpm")
        print()

    # HRV
    if "hrv" in metrics:
        hrv = metrics["hrv"]
        print(f"📈 HRV (Heart Rate Variability):")
        if hrv.get('hrv_value'):
            print(f"   HRV: {hrv.get('hrv_value'):.1f} ms")
        if hrv.get('status'):
            print(f"   Status: {hrv.get('status')}")
        print()

    # Stress
    if "stress" in metrics:
        stress = metrics["stress"]
        print(f"😰 Stress:")
        if stress.get('average_stress_level') is not None:
            print(f"   Average Stress: {stress.get('average_stress_level')}/100")
        if stress.get('max_stress_level') is not None:
            print(f"   Max Stress: {stress.get('max_stress_level')}/100")
        print()

    # Body Battery
    if "body_battery" in metrics:
        bb = metrics["body_battery"]
        print(f"🔋 Body Battery:")
        if bb.get('charged'):
            print(f"   Charged: +{bb.get('charged')}")
        if bb.get('drained'):
            print(f"   Drained: -{bb.get('drained')}")
        if bb.get('highest_value') is not None:
            print(f"   Highest: {bb.get('highest_value')}/100")
        if bb.get('lowest_value') is not None:
            print(f"   Lowest: {bb.get('lowest_value')}/100")
        print()

    # Weight
    if "weight" in metrics:
        weight = metrics["weight"]
        print(f"⚖️  Weight:")
        if weight.get('weight_kg'):
            print(f"   Weight: {weight.get('weight_kg')} kg")
        if weight.get('bmi'):
            print(f"   BMI: {weight.get('bmi'):.1f}")
        if weight.get('body_fat_percentage'):
            print(f"   Body Fat: {weight.get('body_fat_percentage'):.1f}%")
        print()

    # Respiration
    if "respiration" in metrics:
        resp = metrics["respiration"]
        print(f"🫁 Respiration:")
        if resp.get('average_respiration_rate'):
            print(f"   Average: {resp.get('average_respiration_rate'):.1f} bpm")
        if resp.get('min_respiration_rate'):
            print(f"   Min: {resp.get('min_respiration_rate'):.1f} bpm")
        if resp.get('max_respiration_rate'):
            print(f"   Max: {resp.get('max_respiration_rate'):.1f} bpm")
        print()

    # SPO2
    if "spo2" in metrics:
        spo2 = metrics["spo2"]
        if spo2.get('average_spo2'):
            print(f"🩸 Blood Oxygen (SpO2):")
            print(f"   Average: {spo2.get('average_spo2'):.1f}%")
            if spo2.get('min_spo2'):
                print(f"   Min: {spo2.get('min_spo2'):.1f}%")
            if spo2.get('max_spo2'):
                print(f"   Max: {spo2.get('max_spo2'):.1f}%")
            print()

    # Floors
    if "floors" in metrics:
        floors = metrics["floors"]
        if floors.get('floors_climbed'):
            print(f"🪜 Floors:")
            print(f"   Climbed: {floors.get('floors_climbed')}")
            if floors.get('floors_descended'):
                print(f"   Descended: {floors.get('floors_descended')}")
            print()

    # Intensity Minutes
    if "intensity_minutes" in metrics:
        im = metrics["intensity_minutes"]
        if im.get('moderate_minutes') is not None or im.get('vigorous_minutes') is not None:
            print(f"⏱️  Intensity Minutes:")
            if im.get('moderate_minutes') is not None:
                print(f"   Moderate: {im.get('moderate_minutes')} min")
            if im.get('vigorous_minutes') is not None:
                print(f"   Vigorous: {im.get('vigorous_minutes')} min")
            if im.get('total_minutes') is not None:
                print(f"   Total: {im.get('total_minutes')} min")
            print()

    # Hydration
    if "hydration" in metrics:
        hydration = metrics["hydration"]
        if hydration.get('total_intake_ml'):
            print(f"💧 Hydration:")
            print(f"   Intake: {hydration.get('total_intake_ml')} ml")
            if hydration.get('goal_ml'):
                print(f"   Goal: {hydration.get('goal_ml')} ml")
            print()

    # RHR (Resting Heart Rate) - if not already shown in heart_rate
    if "rhr" in metrics and "heart_rate" not in metrics:
        rhr = metrics["rhr"]
        if rhr.get('resting_heart_rate'):
            print(f"❤️  Resting Heart Rate:")
            print(f"   RHR: {rhr.get('resting_heart_rate')} bpm")
            print()

    # Activities
    activities = summary.get("activities", [])
    if activities:
        print(f"🏃 Activities ({len(activities)}):")
        for activity in activities:
            activity_type = activity.get("activity_type", "Unknown")
            duration = format_seconds_to_hms(activity.get("duration_seconds"))
            distance = activity.get("distance_meters")

            activity_str = f"   • {activity_type}: {duration}"
            if distance:
                activity_str += f", {distance / 1000:.2f} km"

            if activity.get("average_heart_rate"):
                activity_str += f", Avg HR: {format_number(activity.get('average_heart_rate'))} bpm"

            print(activity_str)
        print()

    print(f"{'='*80}\n")


def print_metric_range(metric_type: str, data_list: List[dict]) -> None:
    """Print a formatted metric range.

    Args:
        metric_type: Type of metric
        data_list: List of metric data
    """
    if not data_list:
        print(f"\n❌ No data found for {metric_type}\n")
        return

    print(f"\n{'='*80}")
    print(f"📊 {metric_type.upper().replace('_', ' ')} - {len(data_list)} records")
    print(f"{'='*80}\n")

    # Define what fields to display for each metric type
    display_configs = {
        "steps": ["date", "total_steps", "total_distance_meters", "calories_burned"],
        "sleep": ["date", "total_sleep_seconds", "deep_sleep_seconds", "sleep_score"],
        "heart_rate": ["date", "resting_heart_rate", "min_heart_rate", "max_heart_rate"],
        "hrv": ["date", "hrv_value", "status"],
        "stress": ["date", "average_stress_level", "max_stress_level"],
        "body_battery": ["date", "charged", "drained", "highest_value", "lowest_value"],
        "weight": ["date", "weight_kg", "bmi", "body_fat_percentage"],
        "rhr": ["date", "resting_heart_rate"],
    }

    fields = display_configs.get(metric_type, ["date"])

    # Print header
    header = " | ".join([f"{field:20}" for field in fields])
    print(header)
    print("-" * len(header))

    # Print data rows
    for data in data_list:
        row = []
        for field in fields:
            value = data.get(field, None)

            # Format specific fields
            if field == "date":
                value = str(value) if value else "N/A"
            elif field.endswith("_seconds"):
                value = format_seconds_to_hms(value)
            elif isinstance(value, float):
                value = format_number(value, decimals=2)
            elif isinstance(value, int):
                value = format_number(value)
            else:
                value = str(value) if value is not None else "N/A"

            row.append(f"{value:20}")

        print(" | ".join(row))

    print(f"\n{'='*80}\n")


@click.group()
def cli() -> None:
    """Health data query CLI."""
    pass


@cli.command()
@click.argument("date_str", required=False)
def daily(date_str: Optional[str] = None) -> None:
    """Show health data summary for a specific day.

    DATE_STR: Date in YYYY-MM-DD format (default: today)

    Examples:
        python -m health.cli.query daily
        python -m health.cli.query daily 2024-01-15
    """
    try:
        # Parse date
        if date_str:
            target_date = datetime.strptime(date_str, "%Y-%m-%d").date()
        else:
            target_date = date.today()

        # Query data
        query_service = HealthDataQuery()
        summary = query_service.get_daily_summary(target_date)

        # Display
        print_daily_summary(summary)

    except ValueError as e:
        click.echo(f"❌ Error: Invalid date format. Use YYYY-MM-DD. {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"❌ Error: {e}", err=True)
        logger.exception("Failed to get daily summary")
        sys.exit(1)


@cli.command()
@click.argument("metric_type")
@click.argument("start_date")
@click.argument("end_date")
@click.option("--stats", is_flag=True, help="Show statistics summary")
def range(metric_type: str, start_date: str, end_date: str, stats: bool) -> None:
    """Show metric data over a date range.

    METRIC_TYPE: Type of metric (e.g., steps, sleep, heart_rate)
    START_DATE: Start date in YYYY-MM-DD format
    END_DATE: End date in YYYY-MM-DD format

    Examples:
        python -m health.cli.query range steps 2024-01-01 2024-01-07
        python -m health.cli.query range sleep 2024-01-01 2024-01-07 --stats
    """
    try:
        # Parse dates
        start = datetime.strptime(start_date, "%Y-%m-%d").date()
        end = datetime.strptime(end_date, "%Y-%m-%d").date()

        if start > end:
            raise ValueError("Start date must be before or equal to end date")

        # Query data
        query_service = HealthDataQuery()
        data_list = query_service.get_metric_range(metric_type, start, end)

        # Display
        print_metric_range(metric_type, data_list)

        # Show statistics if requested
        if stats and data_list:
            # Determine which fields to analyze
            field_configs = {
                "steps": ["total_steps", "total_distance_meters", "calories_burned"],
                "sleep": ["total_sleep_seconds", "deep_sleep_seconds", "sleep_score"],
                "heart_rate": ["resting_heart_rate", "min_heart_rate", "max_heart_rate"],
                "hrv": ["hrv_value"],
                "stress": ["average_stress_level", "max_stress_level"],
                "body_battery": ["charged", "drained", "highest_value"],
                "weight": ["weight", "bmi", "body_fat_percentage"],
            }

            fields = field_configs.get(metric_type, [])
            if fields:
                statistics = query_service.get_metric_statistics(metric_type, start, end, fields)

                print(f"📈 Statistics Summary:\n")
                for field, stat in statistics.items():
                    if stat["count"] > 0:
                        print(f"{field}:")
                        print(f"  Min: {stat['min']}")
                        print(f"  Max: {stat['max']}")
                        print(f"  Avg: {stat['avg']:.2f}")
                        print(f"  Count: {stat['count']}")
                        print()

    except ValueError as e:
        click.echo(f"❌ Error: {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"❌ Error: {e}", err=True)
        logger.exception("Failed to get metric range")
        sys.exit(1)


@cli.command()
@click.argument("start_date")
@click.argument("end_date")
@click.option("--type", "activity_type", help="Filter by activity type")
def activities(start_date: str, end_date: str, activity_type: Optional[str] = None) -> None:
    """Show activities within a date range.

    START_DATE: Start date in YYYY-MM-DD format
    END_DATE: End date in YYYY-MM-DD format

    Examples:
        python -m health.cli.query activities 2024-01-01 2024-01-07
        python -m health.cli.query activities 2024-01-01 2024-01-07 --type running
    """
    try:
        # Parse dates
        start = datetime.strptime(start_date, "%Y-%m-%d").date()
        end = datetime.strptime(end_date, "%Y-%m-%d").date()

        if start > end:
            raise ValueError("Start date must be before or equal to end date")

        # Query data
        query_service = HealthDataQuery()
        activities_list = query_service.get_activities_range(start, end, activity_type)

        if not activities_list:
            print(f"\n❌ No activities found\n")
            return

        print(f"\n{'='*80}")
        print(f"🏃 Activities ({len(activities_list)} found)")
        print(f"{'='*80}\n")

        for activity in activities_list:
            print(f"📅 {activity.get('date')} - {activity.get('activity_type', 'Unknown')}")
            print(f"   Duration: {format_seconds_to_hms(activity.get('duration_seconds'))}")

            if activity.get('distance_meters'):
                print(f"   Distance: {activity.get('distance_meters') / 1000:.2f} km")

            if activity.get('average_heart_rate'):
                print(f"   Avg HR: {format_number(activity.get('average_heart_rate'))} bpm")

            if activity.get('max_heart_rate'):
                print(f"   Max HR: {format_number(activity.get('max_heart_rate'))} bpm")

            if activity.get('calories'):
                print(f"   Calories: {format_number(activity.get('calories'))} kcal")

            print()

        print(f"{'='*80}\n")

    except ValueError as e:
        click.echo(f"❌ Error: {e}", err=True)
        sys.exit(1)
    except Exception as e:
        click.echo(f"❌ Error: {e}", err=True)
        logger.exception("Failed to get activities")
        sys.exit(1)


@cli.command()
def types() -> None:
    """List all available metric types."""
    print("\n📋 Available Metric Types:\n")

    for metric_type, type_config in config.DATA_TYPE_CONFIG.items():
        print(f"  • {metric_type:20} - {type_config['description']}")

    print()


if __name__ == "__main__":
    cli()
