"""
Example of using the soildb.awdb module to fetch data for various station types.

This example demonstrates the enhanced AWDB client with:
- Semantic property names instead of cryptic element codes
- Comprehensive sensor metadata reporting
- Improved station filtering and data retrieval
- Support for all AWDB API parameters and response fields
- Automatic sensor selection and dynamic property discovery
"""

import asyncio

from soildb.awdb.convenience import (
    find_stations_by_criteria,
    get_monitoring_station_data,
    get_nearby_stations,
    list_available_variables,
)


async def fetch_and_print_data(
    client,
    network_code,
    property_name,
    start_date="2023-01-01",
    end_date="2023-01-10",
    height_depth_inches=None,
    state_codes=None,
    max_stations=3,
):
    """
    Fetches and prints data for a given network and property.
    Updated to use proper API element format for soil properties.
    """
    print(f"\n--- Example: Fetching {property_name} for {network_code} network ---")

    # Get stations for this network (now using API filtering)
    stations = await client.get_stations(
        network_codes=[network_code], state_codes=state_codes, active_only=True
    )

    if not stations:
        print(f"No active stations found for network: {network_code}")
        return

    print(f"Found {len(stations)} active {network_code} stations total.")
    stations = stations[:max_stations]  # Limit to first few stations
    print(f"Testing data retrieval for first {len(stations)} {network_code} stations.")

    # Try to get data from each station directly
    for station in stations:
        try:
            print(f"\nTrying station: {station.name} ({station.station_triplet})")

            # Get the element code for this property
            from soildb.awdb.convenience import (
                PROPERTY_ELEMENT_MAP,
                SOIL_PROPERTIES,
                build_soil_element_string,
            )

            if property_name not in PROPERTY_ELEMENT_MAP:
                print(f"Unknown property: {property_name}")
                continue

            element_code = PROPERTY_ELEMENT_MAP[property_name]

            # Build proper element string for soil properties
            if property_name in SOIL_PROPERTIES:
                if height_depth_inches is None:
                    print(
                        f"   Soil property '{property_name}' requires height_depth_inches parameter"
                    )
                    continue
                element_string = build_soil_element_string(
                    element_code, height_depth_inches, ordinal=1
                )
                print(f"   Using element: {element_string}")
            else:
                element_string = element_code

            # Get data directly from this specific station
            raw_data = await client.get_station_data(
                station.station_triplet,
                element_string,
                start_date,
                end_date,
                ordinal=1,
            )

            if raw_data:
                print(
                    f" Successfully fetched {len(raw_data)} data points for {station.name}"
                )
                print(f"   Sample: {raw_data[0]}")
                break  # Found data, stop trying other stations
            else:
                print(f"   No data available for {station.name} in date range")

        except Exception as e:
            print(f"    Failed to fetch data for {station.name}: {e}")

    else:
        print(
            f"\n Could not find any {network_code} station with data for the specified criteria."
        )
        if network_code == "SNOW":
            print(
                "   NOTE: SNOW network data is manually collected and may not be available for all stations or date ranges."
            )


async def run_awdb_example():
    """
    Fetches data for various station types using the soildb.awdb module.
    Demonstrates automatic sensor selection and sensor metadata features.
    """
    print("Fetching station data from AWDB...")
    print("Note: This example demonstrates automatic sensor selection and")
    print("sensor metadata discovery features.\n")

    # Example 1: Automatic sensor selection for soil moisture
    print("=== Example 1: Automatic Sensor Selection ===")
    print("Finding nearby stations with sensor metadata...")

    try:
        stations = await get_nearby_stations(
            latitude=39.7392,  # Denver, CO
            longitude=-104.9903,
            max_distance_km=50,
            network_codes=["SCAN"],
            limit=3,
            include_sensor_metadata=True,
        )

        print(f"Found {len(stations)} SCAN stations with sensor metadata:")
        for station in stations:
            print(f"\nStation: {station['name']} ({station['station_triplet']})")
            print(f"Distance: {station['distance_km']} km")

            if "sensor_metadata" in station and station["sensor_metadata"]:
                sensors = station["sensor_metadata"]
                print("Available sensors:")
                for prop_name, sensor_list in sensors.items():
                    print(f"  {prop_name}: {len(sensor_list)} sensors")
                    for sensor in sensor_list[:2]:  # Show first 2
                        depth = sensor.get("height_depth_inches", "N/A")
                        ordinal = sensor.get("ordinal", "N/A")
                        print(f'    Depth: {depth}", Ordinal: {ordinal}')
            else:
                print("  No sensor metadata available")

    except Exception as e:
        print(f"Error getting nearby stations: {e}")

    # Example 2: Auto sensor selection for soil moisture
    print("\n\n=== Example 2: Auto Sensor Selection for Soil Moisture ===")
    print("Automatically selecting best available soil moisture sensor...")

    try:
        result = await get_monitoring_station_data(
            latitude=39.7392,
            longitude=-104.9903,
            property_name="soil_moisture",
            start_date="2023-10-01",
            end_date="2023-10-05",
            auto_select_sensor=True,  # This is the key new feature!
        )

        print("Success with auto sensor selection.")
        print(f"Station: {result['site_name']} ({result['site_id']})")
        print(f"Distance: {result['metadata']['distance_km']} km")
        print(f"Auto-selected element: {result['metadata']['element_string']}")
        print(f"Data points: {len(result['data_points'])}")
        print(f"Unit: {result.get('unit', 'N/A')}")

        if result["data_points"]:
            sample = result["data_points"][0]
            print(
                f"Sample: {sample['timestamp'][:10]} = {sample['value']} {result.get('unit', '')}"
            )

    except Exception as e:
        print(f"Auto sensor selection failed: {e}")

    # Example 3: Traditional manual sensor specification still works
    print("\n\n=== Example 3: Manual Sensor Specification (Traditional) ===")
    print("Manually specifying sensor depth...")

    try:
        result = await get_monitoring_station_data(
            latitude=39.7392,
            longitude=-104.9903,
            property_name="air_temp",
            start_date="2023-01-01",
            end_date="2023-01-05",
            height_depth_inches=10,  # 10 feet above ground
            auto_select_sensor=False,  # Explicitly disable auto-selection
        )

        print("Success with manual sensor specification.")
        print(f"Station: {result['site_name']} ({result['site_id']})")
        print(f"Element used: {result['metadata']['element_string']}")
        print(f"Data points: {len(result['data_points'])}")

    except Exception as e:
        print(f"Manual sensor specification failed: {e}")

    # Example 4: Advanced station filtering with sensor metadata
    print("\n\n=== Example 4: Advanced Station Filtering ===")
    print("Finding SCAN stations in Colorado with sensor metadata...")

    try:
        stations = await find_stations_by_criteria(
            network_codes=["SCAN"],
            state_codes=["CO"],
            active_only=True,
            limit=5,
            include_sensor_metadata=True,
        )

        print(f"Found {len(stations)} SCAN stations with sensor metadata:")
        for station in stations:
            sensor_types = []
            if "sensor_metadata" in station:
                sensor_types = list(station["sensor_metadata"].keys())

            print(
                f"  {station['name']} ({station['station_triplet']}): {len(sensor_types)} sensor types"
            )
            if sensor_types:
                print(f"    Available: {', '.join(sensor_types[:3])}")  # Show first 3

    except Exception as e:
        print(f"Advanced filtering failed: {e}")

    # Example 5: Comprehensive sensor inventory for a station
    print("\n\n=== Example 5: Complete Sensor Inventory ===")
    print("Getting comprehensive sensor inventory for a SCAN station...")

    try:
        # Use a station we know has comprehensive sensors
        station_triplet = "2197:CO:SCAN"  # CPER station

        variables = await list_available_variables(station_triplet)

        print(
            f"Station {station_triplet} has {len(variables)} different variable types:"
        )
        print()

        # Group by known vs unknown
        known_vars = [
            v for v in variables if not v["property_name"].startswith("unknown_")
        ]
        unknown_vars = [
            v for v in variables if v["property_name"].startswith("unknown_")
        ]

        print(f"Known properties ({len(known_vars)}):")
        for var in known_vars[:8]:  # Show first 8
            prop_name = var["property_name"]
            element_code = var["element_code"]
            unit = var["unit"]
            sensor_count = len(var["sensors"])
            print(f"  {prop_name} ({element_code}): {unit}, {sensor_count} sensors")

        if len(known_vars) > 8:
            print(f"  ... and {len(known_vars) - 8} more known properties")

        if unknown_vars:
            print(f"\nUnknown properties ({len(unknown_vars)}):")
            for var in unknown_vars[:3]:  # Show first 3
                prop_name = var["property_name"]
                element_code = var["element_code"]
                sensor_count = len(var["sensors"])
                print(f"  {prop_name} ({element_code}): {sensor_count} sensors")

    except Exception as e:
        print(f"Comprehensive inventory failed: {e}")

    print("\n\n=== Summary ===")
    print("Automatic sensor selection eliminates guesswork")
    print("Sensor metadata provides complete station inventories")
    print("Backward compatibility maintained for manual specification")
    print("Advanced filtering works with sensor metadata")
    print("Comprehensive property mapping covers all AWDB sensor types")
    print("Dynamic property discovery handles unknown elements gracefully")
    print("Enhanced AWDB client supports all API parameters and features")


async def fetch_soil_moisture_example(client):
    """
    Demonstrate soil moisture data retrieval using proper API format.
    """
    from soildb.awdb.convenience import (
        get_monitoring_station_data,
        get_soil_moisture_data,
        get_station_soil_depths,
    )

    station_triplet = "2057:AL:SCAN"

    try:
        print(f"Station: {station_triplet} (Alabama Hills SCAN)")

        # Get available soil depths
        depths = await get_station_soil_depths(station_triplet, "soil_moisture")
        print(f"Available soil moisture depths: {len(depths)}")

        for depth in depths[:5]:  # Show first 5 depths
            d_inches = depth["height_depth_inches"]
            ordinal = depth["ordinal"]
            element = depth["element_string"]
            print(f'  {d_inches}": ordinal {ordinal}, element: {element}')

        if depths:
            # Demonstrate single depth query using get_monitoring_station_data
            print("\n--- Single Depth Query (using get_monitoring_station_data) ---")
            try:
                # Get data for 20-inch depth
                result = await get_monitoring_station_data(
                    latitude=36.6,  # Approximate location of Alabama Hills
                    longitude=-118.1,
                    property_name="soil_moisture",
                    start_date="2024-09-01",
                    end_date="2024-10-01",
                    height_depth_inches=-20,  # 20 inches deep
                    max_distance_km=100,  # Allow wider search
                )

                print(f" Found station: {result['site_name']} ({result['site_id']})")
                print(f"   Distance: {result['metadata']['distance_km']} km")
                print(f"   Data points: {result['metadata']['n_data_points']}")
                print(f"   Element used: {result['metadata']['element_string']}")

                if result["data_points"]:
                    sample = result["data_points"][0]
                    print(
                        f"   Sample: {sample['timestamp'][:10]} = {sample['value']}% volumetric moisture"
                    )

            except Exception as e:
                print(f" Single depth query failed: {e}")

            # Get soil moisture data for multiple depths
            print("\n--- Multi-Depth Query (using get_soil_moisture_data) ---")

            soil_data = await get_soil_moisture_data(
                station_triplet,
                depths_inches=[-40, -20, -8, -4, -2],  # Specific depths
                start_date="2024-09-01",
                end_date="2024-10-01",
            )

            print(f"Retrieved data for {len(soil_data['depths'])} depths:")

            for depth_inches, depth_data in soil_data["depths"].items():
                n_points = depth_data["n_data_points"]
                element = depth_data["element_string"]
                if n_points > 0:
                    print(f' Depth {depth_inches}": {n_points} points')
                    # Show sample value
                    if depth_data["data_points"]:
                        sample = depth_data["data_points"][0]
                        print(
                            f"   Sample: {sample['timestamp'][:10]} = {sample['value']}%"
                        )
                else:
                    error = depth_data.get("error", "No data")
                    print(f' Depth {depth_inches}": {error}')

        else:
            print("   No soil moisture sensors found")

    except Exception as e:
        print(f" Error in soil moisture example: {e}")


async def fetch_data_for_known_station(
    client, station_triplet, element_code, description
):
    """
    Fetch data for a specific known station and element.
    """
    try:
        print(f"Trying station: {station_triplet} ({description})")

        # Get data directly from this specific station
        raw_data = await client.get_station_data(
            station_triplet, element_code, "2023-01-01", "2023-01-05"
        )

        if raw_data:
            print(f" Successfully fetched {len(raw_data)} data points")
            print(f"   Sample: {raw_data[0]}")
        else:
            print("   No data available for date range")

    except Exception as e:
        print(f" Error fetching data: {e}")


if __name__ == "__main__":
    asyncio.run(run_awdb_example())
