"""
British Gas Tariff API

Provides functions to read cached British Gas tariff data
for use in the main bill analyser application.

Usage:
    from scraper.british_gas_api import get_british_gas_tariffs, find_best_tariff

    # Get all tariffs for a region
    tariffs = get_british_gas_tariffs(postcode="HP20 1HP")

    # Find best matching tariff
    best = find_best_tariff(
        postcode="HP20 1HP",
        annual_electricity_kwh=2900,
        annual_gas_kwh=12000
    )
"""

import json
from pathlib import Path
from typing import Optional, List, Dict
from datetime import datetime, timedelta

# Import DNO lookup for postcode-to-region mapping
try:
    from .dno_lookup import get_dno_for_postcode, find_matching_region
except ImportError:
    from dno_lookup import get_dno_for_postcode, find_matching_region


# Path to cached tariff data
TARIFF_FILE = Path(__file__).parent / "output" / "british-gas-tariffs.json"
CACHE_MAX_AGE_HOURS = 24


def get_cached_data() -> Optional[dict]:
    """
    Load cached British Gas tariff data.

    Returns:
        Dictionary with tariff data, or None if not available/stale
    """
    if not TARIFF_FILE.exists():
        return None

    try:
        with open(TARIFF_FILE, 'r') as f:
            data = json.load(f)

        # Check if data is stale (older than 24 hours)
        scraped_at = data.get("scraped_at")
        if scraped_at:
            scraped_time = datetime.fromisoformat(scraped_at.replace('Z', '+00:00'))
            age = datetime.now(scraped_time.tzinfo) - scraped_time
            if age > timedelta(hours=CACHE_MAX_AGE_HOURS):
                return None  # Data is stale

        return data
    except Exception:
        return None


def get_british_gas_tariffs(postcode: str = None, region: str = None) -> List[dict]:
    """
    Get British Gas tariffs, optionally filtered by postcode or region.

    Uses DNO lookup to accurately match postcodes to their electricity
    distribution region, ensuring users see correct regional pricing.

    Args:
        postcode: UK postcode to find regional tariffs
        region: Region name (alternative to postcode)

    Returns:
        List of tariff dictionaries for the matched region
    """
    data = get_cached_data()
    if not data:
        return []

    regions = data.get("regions", [])

    # If no filter, return first successful region's tariffs
    if not postcode and not region:
        for r in regions:
            if r.get("success") and r.get("tariffs"):
                return r["tariffs"]
        return []

    # Use DNO lookup for accurate postcode-to-region mapping
    if postcode:
        dno_info = get_dno_for_postcode(postcode)
        target_region = dno_info.get("region")

        if target_region:
            # Find matching cached region data
            available_regions = [r.get("region") for r in regions if r.get("success")]
            matched_region = find_matching_region(postcode, available_regions)

            # Look for exact region match first
            for r in regions:
                if r.get("success") and r.get("region") == matched_region:
                    return r.get("tariffs", [])

    # Filter by region name if provided
    if region:
        for r in regions:
            if not r.get("success"):
                continue
            r_region = r.get("region", "").lower()
            if region.lower() in r_region or r_region in region.lower():
                return r.get("tariffs", [])

    # Fallback: return any available tariffs
    for r in regions:
        if r.get("success") and r.get("tariffs"):
            return r["tariffs"]

    return []


def get_tariffs_with_region_info(postcode: str) -> Dict:
    """
    Get British Gas tariffs with detailed region matching info.

    Args:
        postcode: UK postcode

    Returns:
        Dictionary with tariffs and region matching details
    """
    dno_info = get_dno_for_postcode(postcode)
    target_region = dno_info.get("region")

    # Try to get tariffs for the specific region
    data = get_cached_data()
    tariffs = []
    using_fallback = False
    actual_region = None

    if data:
        regions = data.get("regions", [])

        # First try exact region match
        for r in regions:
            if r.get("success") and r.get("region") == target_region:
                tariffs = r.get("tariffs", [])
                actual_region = r.get("region")
                break

        # If no match, use fallback (any available region)
        if not tariffs:
            for r in regions:
                if r.get("success") and r.get("tariffs"):
                    tariffs = r.get("tariffs", [])
                    actual_region = r.get("region")
                    using_fallback = True
                    break

    return {
        "postcode": postcode,
        "dno": {
            "code": dno_info.get("dno_code"),
            "name": dno_info.get("dno_name"),
            "region": dno_info.get("region"),
            "postcode_prefix": dno_info.get("postcode_prefix")
        },
        "tariffs": tariffs,
        "tariff_count": len(tariffs),
        "using_fallback": using_fallback,
        "actual_region": actual_region,
        "note": "Using national tariffs from fallback region" if using_fallback else None
    }


def calculate_annual_cost(
    tariff: dict,
    annual_electricity_kwh: float,
    annual_gas_kwh: float = 0
) -> float:
    """
    Calculate annual cost for a tariff based on usage.

    Args:
        tariff: Tariff dictionary with rates
        annual_electricity_kwh: Annual electricity usage in kWh
        annual_gas_kwh: Annual gas usage in kWh (0 for electricity only)

    Returns:
        Estimated annual cost in pounds
    """
    elec = tariff.get("electricity", {})
    gas = tariff.get("gas", {})

    # Electricity cost
    elec_unit_rate = elec.get("unit_rate_pence", 0) or 0
    elec_standing = elec.get("standing_charge_pence", 0) or 0

    elec_cost = (annual_electricity_kwh * elec_unit_rate / 100) + (365 * elec_standing / 100)

    # Gas cost (if applicable)
    gas_cost = 0
    if annual_gas_kwh > 0:
        gas_unit_rate = gas.get("unit_rate_pence", 0) or 0
        gas_standing = gas.get("standing_charge_pence", 0) or 0
        gas_cost = (annual_gas_kwh * gas_unit_rate / 100) + (365 * gas_standing / 100)

    return round(elec_cost + gas_cost, 2)


def find_best_tariff(
    postcode: str = None,
    annual_electricity_kwh: float = 2900,
    annual_gas_kwh: float = 12000,
    tariff_type: str = None
) -> Optional[dict]:
    """
    Find the best (cheapest) British Gas tariff for given usage.

    Args:
        postcode: Postcode to find regional tariffs
        annual_electricity_kwh: Annual electricity usage (default: UK average)
        annual_gas_kwh: Annual gas usage (default: UK average, 0 for elec only)
        tariff_type: Filter by type ("Fixed", "Variable", etc.)

    Returns:
        Best tariff with calculated cost, or None if no tariffs available
    """
    tariffs = get_british_gas_tariffs(postcode=postcode)

    if not tariffs:
        return None

    # Filter by type if specified
    if tariff_type:
        tariffs = [t for t in tariffs if t.get("type", "").lower() == tariff_type.lower()]

    if not tariffs:
        return None

    # Calculate cost for each tariff
    best = None
    best_cost = float('inf')

    for tariff in tariffs:
        cost = calculate_annual_cost(tariff, annual_electricity_kwh, annual_gas_kwh)
        if cost < best_cost:
            best_cost = cost
            best = {
                **tariff,
                "calculated_annual_cost": cost,
                "usage": {
                    "electricity_kwh": annual_electricity_kwh,
                    "gas_kwh": annual_gas_kwh
                }
            }

    return best


def compare_tariffs(
    current_annual_cost: float,
    postcode: str = None,
    annual_electricity_kwh: float = 2900,
    annual_gas_kwh: float = 12000
) -> Dict:
    """
    Compare current tariff cost against British Gas options.

    Args:
        current_annual_cost: Current annual energy cost in pounds
        postcode: Postcode for regional tariffs
        annual_electricity_kwh: Annual electricity usage
        annual_gas_kwh: Annual gas usage

    Returns:
        Comparison results with potential savings
    """
    tariffs = get_british_gas_tariffs(postcode=postcode)

    if not tariffs:
        return {
            "available": False,
            "message": "British Gas tariff data not available. Run the scraper to update."
        }

    comparisons = []
    for tariff in tariffs:
        cost = calculate_annual_cost(tariff, annual_electricity_kwh, annual_gas_kwh)
        saving = current_annual_cost - cost

        comparisons.append({
            "name": tariff.get("name"),
            "type": tariff.get("type"),
            "annual_cost": cost,
            "saving": round(saving, 2),
            "is_cheaper": saving > 0,
            "electricity": tariff.get("electricity"),
            "gas": tariff.get("gas")
        })

    # Sort by annual cost (cheapest first)
    comparisons.sort(key=lambda x: x["annual_cost"])

    best = comparisons[0] if comparisons else None

    return {
        "available": True,
        "current_cost": current_annual_cost,
        "best_tariff": best,
        "all_tariffs": comparisons,
        "potential_saving": best["saving"] if best and best["is_cheaper"] else 0
    }


def get_ev_tariff(postcode: str = None, region: str = None) -> Optional[Dict]:
    """
    Get British Gas EV Power tariff for a region.

    The EV tariff has time-of-use pricing:
    - Peak rate: Standard daytime electricity rate
    - Off-peak rate: Cheaper overnight rate (12am-5am)

    Args:
        postcode: UK postcode to find regional EV tariff
        region: Region name (alternative to postcode)

    Returns:
        EV tariff dictionary with peak/off-peak rates, or None if not available
    """
    data = get_cached_data()
    if not data:
        return None

    regions = data.get("regions", [])

    # Use DNO lookup for accurate postcode-to-region mapping
    if postcode:
        dno_info = get_dno_for_postcode(postcode)
        target_region = dno_info.get("region")

        if target_region:
            available_regions = [r.get("region") for r in regions if r.get("success")]
            matched_region = find_matching_region(postcode, available_regions)

            for r in regions:
                if r.get("success") and r.get("region") == matched_region:
                    return r.get("ev_tariff")

    # Filter by region name if provided
    if region:
        for r in regions:
            if not r.get("success"):
                continue
            r_region = r.get("region", "").lower()
            if region.lower() in r_region or r_region in region.lower():
                return r.get("ev_tariff")

    # Fallback: return any available EV tariff
    for r in regions:
        if r.get("success") and r.get("ev_tariff"):
            return r["ev_tariff"]

    return None


def calculate_ev_annual_cost(
    ev_tariff: dict,
    annual_electricity_kwh: float,
    annual_gas_kwh: float = 0,
    off_peak_percentage: float = 0.5
) -> Dict:
    """
    Calculate annual cost for an EV tariff with peak/off-peak split.

    Args:
        ev_tariff: EV tariff dictionary with peak/off-peak rates
        annual_electricity_kwh: Total annual electricity usage in kWh
        annual_gas_kwh: Annual gas usage in kWh (0 for electricity only)
        off_peak_percentage: Fraction of electricity used during off-peak (0.0-1.0)
                            Default 0.5 assumes 50% overnight charging

    Returns:
        Dictionary with cost breakdown
    """
    elec = ev_tariff.get("electricity", {})
    gas = ev_tariff.get("gas", {})

    # Split electricity usage between peak and off-peak
    off_peak_kwh = annual_electricity_kwh * off_peak_percentage
    peak_kwh = annual_electricity_kwh * (1 - off_peak_percentage)

    # Get rates (with fallbacks)
    peak_rate = elec.get("peak_unit_rate_pence", 0) or 0
    off_peak_rate = elec.get("off_peak_unit_rate_pence", 0) or 0
    elec_standing = elec.get("standing_charge_pence", 0) or 0

    # Calculate electricity costs
    peak_cost = peak_kwh * peak_rate / 100
    off_peak_cost = off_peak_kwh * off_peak_rate / 100
    elec_standing_cost = 365 * elec_standing / 100
    total_elec_cost = peak_cost + off_peak_cost + elec_standing_cost

    # Gas cost (if applicable)
    gas_cost = 0
    if annual_gas_kwh > 0:
        gas_unit_rate = gas.get("unit_rate_pence", 0) or 0
        gas_standing = gas.get("standing_charge_pence", 0) or 0
        gas_cost = (annual_gas_kwh * gas_unit_rate / 100) + (365 * gas_standing / 100)

    total_cost = total_elec_cost + gas_cost

    return {
        "annual_cost": round(total_cost, 2),
        "electricity": {
            "peak_kwh": round(peak_kwh, 1),
            "peak_cost": round(peak_cost, 2),
            "off_peak_kwh": round(off_peak_kwh, 1),
            "off_peak_cost": round(off_peak_cost, 2),
            "standing_charge_cost": round(elec_standing_cost, 2),
            "total": round(total_elec_cost, 2)
        },
        "gas": {
            "kwh": annual_gas_kwh,
            "total": round(gas_cost, 2)
        },
        "off_peak_percentage": off_peak_percentage,
        "savings_from_off_peak": round((peak_kwh * peak_rate / 100) - (peak_kwh * off_peak_rate / 100), 2)
    }


def compare_ev_tariff(
    current_annual_cost: float,
    postcode: str = None,
    annual_electricity_kwh: float = 2900,
    annual_gas_kwh: float = 12000,
    off_peak_percentage: float = 0.5
) -> Dict:
    """
    Compare current tariff cost against British Gas EV Power tariff.

    Useful for EV owners to see if switching to time-of-use pricing saves money.

    Args:
        current_annual_cost: Current annual energy cost in pounds
        postcode: Postcode for regional tariffs
        annual_electricity_kwh: Annual electricity usage
        annual_gas_kwh: Annual gas usage
        off_peak_percentage: Fraction of electricity used during off-peak hours

    Returns:
        Comparison results with potential savings
    """
    ev_tariff = get_ev_tariff(postcode=postcode)

    if not ev_tariff:
        return {
            "available": False,
            "message": "British Gas EV tariff data not available. Run the scraper to update."
        }

    cost_breakdown = calculate_ev_annual_cost(
        ev_tariff,
        annual_electricity_kwh,
        annual_gas_kwh,
        off_peak_percentage
    )

    ev_cost = cost_breakdown["annual_cost"]
    saving = current_annual_cost - ev_cost

    return {
        "available": True,
        "current_cost": current_annual_cost,
        "ev_tariff": {
            "name": ev_tariff.get("name", "EV Power Tariff"),
            "type": "EV",
            "annual_cost": ev_cost,
            "saving": round(saving, 2),
            "is_cheaper": saving > 0,
            "rates": {
                "electricity_peak_pence": ev_tariff.get("electricity", {}).get("peak_unit_rate_pence"),
                "electricity_off_peak_pence": ev_tariff.get("electricity", {}).get("off_peak_unit_rate_pence"),
                "electricity_standing_pence": ev_tariff.get("electricity", {}).get("standing_charge_pence"),
                "gas_unit_pence": ev_tariff.get("gas", {}).get("unit_rate_pence"),
                "gas_standing_pence": ev_tariff.get("gas", {}).get("standing_charge_pence")
            },
            "cost_breakdown": cost_breakdown
        },
        "potential_saving": saving if saving > 0 else 0,
        "recommendation": _get_ev_recommendation(saving, off_peak_percentage)
    }


def _get_ev_recommendation(saving: float, off_peak_percentage: float) -> str:
    """Generate a plain English recommendation for EV tariff."""
    if saving > 100:
        return f"This could save you £{round(saving)}/year. Great for EV owners who charge overnight."
    elif saving > 0:
        return f"Small saving of £{round(saving)}/year. Consider if you can shift more usage to off-peak hours."
    elif saving > -50:
        return "Similar cost to your current tariff. Only worth switching if you can increase overnight charging."
    else:
        return f"Would cost £{round(-saving)}/year more. Not recommended unless you can charge mostly overnight."


def get_data_freshness() -> Dict:
    """
    Check how fresh the cached data is.

    Returns:
        Dictionary with freshness information
    """
    if not TARIFF_FILE.exists():
        return {
            "available": False,
            "message": "No cached data. Run: python british_gas_scraper.py --all"
        }

    try:
        with open(TARIFF_FILE, 'r') as f:
            data = json.load(f)

        scraped_at = data.get("scraped_at")
        if scraped_at:
            scraped_time = datetime.fromisoformat(scraped_at.replace('Z', '+00:00'))
            age = datetime.now(scraped_time.tzinfo) - scraped_time

            return {
                "available": True,
                "scraped_at": scraped_at,
                "age_hours": round(age.total_seconds() / 3600, 1),
                "is_fresh": age < timedelta(hours=CACHE_MAX_AGE_HOURS),
                "regions_count": len(data.get("regions", []))
            }
    except Exception as e:
        return {
            "available": False,
            "message": f"Error reading cache: {e}"
        }


# Example usage
if __name__ == "__main__":
    print("British Gas Tariff API")
    print("=" * 50)

    # Check data freshness
    freshness = get_data_freshness()
    print(f"\nData freshness: {freshness}")

    # Get tariffs
    tariffs = get_british_gas_tariffs()
    print(f"\nAvailable tariffs: {len(tariffs)}")

    for t in tariffs:
        print(f"  - {t['name']}: £{t.get('annual_cost', 'N/A')}/year")

    # Find best tariff
    best = find_best_tariff(annual_electricity_kwh=3000, annual_gas_kwh=12000)
    if best:
        print(f"\nBest tariff for 3000 kWh elec + 12000 kWh gas:")
        print(f"  {best['name']}: £{best['calculated_annual_cost']}/year")

    # Compare against current cost
    comparison = compare_tariffs(
        current_annual_cost=1800,
        annual_electricity_kwh=3000,
        annual_gas_kwh=12000
    )
    if comparison.get("available"):
        print(f"\nCompared to £1800/year current cost:")
        print(f"  Best: {comparison['best_tariff']['name']}")
        print(f"  Potential saving: £{comparison['potential_saving']}/year")
