
import os
import time
import requests
import pandas as pd
import yfinance as yf
import numpy as np
from scipy import stats


# ================================
# Resilience Layer
# ================================

def safe_request(url, retries=3, delay=2):
    """
    Network resilience wrapper.
    Retries API call on failure.
    """

    last_error = None

    for _ in range(retries):
        try:
            response = requests.get(url, timeout=10)
            if response.status_code == 200:
                return response
        except requests.exceptions.RequestException as e:
            last_error = e

        time.sleep(delay)

    raise Exception(f"API request failed after retries. Last error: {last_error}")


# ================================
# Reliability Layer
# ================================

def verify_dataset_integrity(df, required_columns=None):

    if df is None or df.empty:
        raise ValueError("Dataset integrity failure: DataFrame is empty")

    if required_columns:
        missing = [c for c in required_columns if c not in df.columns]
        if missing:
            raise ValueError(f"Missing required columns: {missing}")

    null_ratio = df.isna().mean()

    if (null_ratio > 0.5).any():
        problematic = null_ratio[null_ratio > 0.5].index.tolist()
        raise ValueError(f"High missing data ratio detected in: {problematic}")

    return True


# ================================
# Main Functions
# ================================

def get_tickers(api_token):

    url = f"https://eodhd.com/api/exchange-symbol-list/JSE?api_token={api_token}&fmt=json"

    response = safe_request(url)
    data = response.json()

    if not data:
        print("Warning: Empty API response")
        return []

    df = pd.json_normalize(data)

    df = df[df["Code"].str.len() <= 3]
    df["ticker"] = df["Code"].astype(str) + ".JO"

    return df["ticker"].tolist()


def download_and_process(tickers, start_date, end_date, output_dir="Stocks"):

    os.makedirs(output_dir, exist_ok=True)

    for ticker in tickers:

        df = yf.download(
            ticker,
            start=start_date,
            end=end_date,
            auto_adjust=True,
            progress=False
        )

        if df is None or df.empty:
            print(f"Skipping {ticker} (no data)")
            continue

        df = df[["Open", "High", "Low", "Close", "Volume"]]

        verify_dataset_integrity(
            df,
            required_columns=["Open", "High", "Low", "Close", "Volume"]
        )

        df = df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]

        df.ffill(inplace=True)
        df.bfill(inplace=True)

        df.to_csv(os.path.join(output_dir, f"{ticker}.csv"))

    print(f"Saved data in '{output_dir}'")


def save_tickers(folder_path):

    tickers = [
        f[:-4]
        for f in os.listdir(folder_path)
        if f.endswith(".csv")
    ]

    df = pd.DataFrame(tickers, columns=["tickers"])
    df.to_csv(os.path.join(folder_path, "tickers.csv"), index=False)

    return df
