import requests
from datetime import datetime, timedelta
import re
from app.db.models import Instrument, KPI, KPIValue

def parse_dotnet_date(dotnet_date_str):
    timestamp = int(re.search(r'\d+', dotnet_date_str).group()) / 1000
    return datetime.utcfromtimestamp(timestamp).date()

def fetch_kpi_data(token, request_body):
    url = "https://product.datastream.com/DSWSClient/V1/DSService.svc/rest/GetDataBundle"
    headers = {"Content-Type": "application/json"}
    print("=============== Request to DataStream API ===============")
    print("Request Body:")
    print(request_body)
    print("Request Headers:")
    print(headers)
    response = requests.post(url, json=request_body, headers=headers)
    print("=============== Response Status Code ===============")
    print(response.status_code)
    print(response.json())
    return response.json()

from dateutil.rrule import rrule, MONTHLY
from dateutil.relativedelta import relativedelta

def generate_date_range(frequency, start, end):
    if frequency == "Q":
        months = [1, 4, 7, 10]
        current = start.replace(day=1)
        dates = []
        while current <= end:
            if current.month in months:
                dates.append(current)
            current += relativedelta(months=1)
        return dates

    elif frequency == "M":
        return [dt.date() for dt in rrule(MONTHLY, dtstart=start, until=end)]

    elif frequency == "Y":
        return [date(start.year + i, 1, 1) for i in range(end.year - start.year + 1)]

    elif frequency == "D":
        return [start + timedelta(days=i) for i in range((end - start).days + 1)]

    else:
        raise ValueError("Invalid frequency")

def find_continuous_ranges(dates, frequency):
    if not dates:
        return []

    dates = sorted(dates)
    ranges = []
    start = prev = dates[0]

    for date in dates[1:]:
        # Define expected next date based on frequency
        if frequency == "Q":
            expected = prev + relativedelta(months=3)
        elif frequency == "M":
            expected = prev + relativedelta(months=1)
        elif frequency == "Y":
            expected = prev + relativedelta(years=1)
        elif frequency == "D":
            expected = prev + timedelta(days=1)
        else:
            raise ValueError("Unsupported frequency")

        if date != expected:
            ranges.append((start, prev))
            start = date
        prev = date

    ranges.append((start, prev))
    return ranges

def store_kpi_response(db, response_json):
    data = response_json.get("DataResponses", [{}])[0]

    if not data or not data.get("DataTypeValues") or not data.get("Dates"):
        print("⚠️ No valid KPI data found in response.")
        return

    try:
        dates = [parse_dotnet_date(d) for d in data["Dates"]]
    except Exception as e:
        print(f"❌ Failed to parse dates: {e}")
        return

    symbol = data["DataTypeValues"][0]["SymbolValues"][0].get("Symbol")
    frequency = None
    for r in data.get("AdditionalResponses", []):
        if r["Key"] == "Frequency":
            frequency = r["Value"]
            break
    if frequency is None:
        print("⚠️ Frequency missing in AdditionalResponses.")
        return

    instrument = db.query(Instrument).filter_by(symbol=symbol).first()
    if not instrument:
        instrument = Instrument(symbol=symbol)
        db.add(instrument)
        db.commit()
        db.refresh(instrument)

    for entry in data["DataTypeValues"]:
        kpi_code = entry["DataType"]
        symbol_value = entry["SymbolValues"][0]
        values = symbol_value.get("Value")
        currency = symbol_value.get("Currency")

        # Defensive: Skip if values is not a list (e.g., "$$ER: 0904,NO DATA AVAILABLE")
        if not isinstance(values, list):
            print(f"⚠️ Skipping KPI '{kpi_code}' for symbol '{symbol}': invalid data -> {values}")
            continue

        kpi = db.query(KPI).filter_by(code=kpi_code).first()
        if not kpi:
            kpi = KPI(code=kpi_code)
            db.add(kpi)
            db.commit()
            db.refresh(kpi)

        for date, value in zip(dates, values):
            if not is_numeric(value):
                continue

            existing = db.query(KPIValue).filter_by(
                instrument_id=instrument.id,
                kpi_id=kpi.id,
                frequency=frequency,
                date=date
            ).first()
            if not existing:
                record = KPIValue(
                    instrument_id=instrument.id,
                    kpi_id=kpi.id,
                    frequency=frequency,
                    date=date,
                    value=value,
                    currency=currency
                )
                db.add(record)
    db.commit()

def is_numeric(val):
    try:
        float(val)
        return True
    except (ValueError, TypeError):
        return False
