# Historical IG data may be downloaded from the following site.
# https://www.dukascopy.com/swiss/english/marketwatch/historical/
# https://forexsb.com/historical-forex-data
#
import argparse
import logging
import os
import re
from collections import defaultdict
from pathlib import Path
from typing import cast

import pandas as pd

logger = logging.getLogger(__name__)

ASSET_MAPPING = {
    "USA500.IDXUSD": "IX.D.SPTRD.IFS.IP",
    "GAS.CMDUSD": "CC.D.NG.UMP.IP",
    "BRENT.CMDUSD": "CC.D.LCO.UMP.IP",
    "USTBOND.TRUSD": "IR.D.10YEAR100.FWM2.IP",
    "COCOA.CMDUSD": "CC.D.CC.UMP.IP",
}

MULTIPLIERS = {
    "USA500.IDXUSD": 1,
    "GAS.CMDUSD": 1000,
    "BRENT.CMDUSD": 100,
    "USTBOND.TRUSD": 100,
    "COCOA.CMDUSD": 1,
}


def cli_app() -> argparse.ArgumentParser:
    app = argparse.ArgumentParser("load-historical-data")

    app.add_argument("--path", type=Path, required=True, nargs="+")
    app.add_argument("--arctic-uri", required=True)
    app.add_argument("--dry-run", action="store_true")
    app.add_argument("--universe", required=True)
    app.add_argument("--provider", required=True)
    app.add_argument("--clean", action="store_true")
    app.add_argument("--end-date", type=pd.Timestamp, default=None)

    return app


# groups: symbol, frequency, field, start_date, end_date
FILE_REGEX = r"^([A-Z0-9\.]+)_Candlestick_([0-9]+_[MDHS])_(BID|ASK)_([0-9]{2}\.[0-9]{2}\.[0-9]{4})-([0-9]{2}\.[0-9]{2}\.[0-9]{4}).csv$"


def read_backfill(
    paths: list[Path],
    end_date: pd.Timestamp | None = None,
) -> tuple[tuple[pd.DataFrame, tuple[str, str]], ...]:
    data_files = defaultdict(list)

    for path in paths:
        for file in os.listdir(path):
            if match := re.match(FILE_REGEX, file):
                symbol, _, field, _, end_date_ = match.groups()
                end_date = cast(pd.Timestamp, end_date_)
                # need to group by symbol
                data_files[(field.lower(), symbol)].append(path / file)

    # symbol, ohlc, symbol
    #
    #
    def read_file(f: str | Path) -> pd.DataFrame:
        logger.warning("Reading %s", f)
        out = pd.read_csv(
            f,
            index_col=0,
            date_format="%d.%m.%Y %H:%M:%S.%f",
        )
        out.index = pd.to_datetime(out.index)
        if isinstance(out.index, pd.DatetimeIndex) and (out.index.name == "Local time"):
            out.index = out.index.tz_convert("utc")  # pyright: ignore
        elif out.index.name == "Gmt time":
            out.index = out.index.tz_localize("GMT").tz_convert(  # pyright: ignore
                "utc"
            )
        else:
            raise ValueError(out.index.name)
        return out.rename_axis("DateTime")

    result = pd.concat(
        (
            pd.concat(read_file(f) for f in files).query("~index.duplicated()")
            for files in data_files.values()
        ),
        axis=1,
        keys=data_files.keys(),
    ).reorder_levels([0, 2, 1], axis=1)

    result = result.mul(pd.Series(MULTIPLIERS), level=2, axis=1)

    result.rename(columns=ASSET_MAPPING, inplace=True)

    if end_date:
        result = result[result.index <= end_date]

    return (
        (result["bid"]["Open"], ("bid", "open")),
        (result["bid"]["High"], ("bid", "high")),
        (result["bid"]["Low"], ("bid", "low")),
        (result["bid"]["Close"], ("bid", "close")),
        (result["ask"]["Open"], ("ask", "open")),
        (result["ask"]["High"], ("ask", "high")),
        (result["ask"]["Low"], ("ask", "low")),
        (result["ask"]["Close"], ("ask", "close")),
        (((result["ask"]["Open"] + result["bid"]["Open"]) / 2), ("mid", "open")),
        (((result["ask"]["High"] + result["bid"]["High"]) / 2), ("mid", "high")),
        (((result["ask"]["Low"] + result["bid"]["Low"]) / 2), ("mid", "low")),
        (((result["ask"]["Close"] + result["bid"]["Close"]) / 2), ("mid", "close")),
    )
