#!/usr/bin/env python3
"""Fetch explicit Yahoo Finance daily-history backfill and emit normalized JSON."""

from __future__ import annotations

import argparse
import json
import re
import sys
from datetime import date, datetime, timedelta, timezone
from decimal import Decimal
from pathlib import Path

import yfinance as yf


CACHE_PATH = Path(__file__).resolve().parents[1] / "storage" / "cache" / "yfinance"


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument("--symbol", required=True)
    parser.add_argument("--from", dest="from_date", required=True)
    parser.add_argument("--to", dest="to_date", required=True)
    parser.add_argument("--timeout", type=int, required=True)
    return parser.parse_args()


def parse_date(value: str) -> date:
    return datetime.strptime(value, "%Y-%m-%d").date()


def decimal_text(value: object) -> str | None:
    if value is None:
        return None
    text = str(value)
    if text.lower() in {"nan", "none"}:
        return None
    return format(Decimal(text), "f")


def main() -> int:
    args = parse_args()
    symbol = args.symbol.strip().upper()
    if re.fullmatch(r"[A-Z0-9.^=\-]{1,32}", symbol) is None:
        raise ValueError("symbol is invalid")
    if args.timeout < 5 or args.timeout > 120:
        raise ValueError("timeout is invalid")

    CACHE_PATH.mkdir(parents=True, exist_ok=True)
    yf.set_tz_cache_location(str(CACHE_PATH))

    from_date = parse_date(args.from_date)
    to_date = parse_date(args.to_date)
    if from_date > to_date:
        raise ValueError("date range is invalid")

    ticker = yf.Ticker(symbol)
    history = ticker.history(
        start=from_date.isoformat(),
        end=(to_date + timedelta(days=1)).isoformat(),
        interval="1d",
        auto_adjust=False,
        actions=False,
        repair=False,
        timeout=args.timeout,
    )
    if history.empty:
        raise RuntimeError("no daily history returned")
    metadata = ticker.get_history_metadata(repair=False)
    currency_code = str(metadata.get("currency", "")).upper().strip()
    if re.fullmatch(r"[A-Z]{3}", currency_code) is None:
        raise ValueError("currency code is unavailable")

    quotes = []
    for timestamp, row in history.iterrows():
        quoted_date = timestamp.date().isoformat()
        close_price = decimal_text(row.get("Close"))
        if close_price is None:
            continue
        volume = row.get("Volume")
        quotes.append(
            {
                "quoted_at": datetime.combine(
                    datetime.strptime(quoted_date, "%Y-%m-%d").date(),
                    datetime.min.time(),
                    tzinfo=timezone.utc,
                ).isoformat(),
                "open_price": decimal_text(row.get("Open")),
                "high_price": decimal_text(row.get("High")),
                "low_price": decimal_text(row.get("Low")),
                "close_price": close_price,
                "adjusted_close_price": decimal_text(row.get("Adj Close")),
                "volume": None if volume is None else int(volume),
            }
        )

    print(json.dumps({"success": True, "currency_code": currency_code, "quotes": quotes}, separators=(",", ":")))
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except Exception as exception:
        print(json.dumps({"success": False, "error": type(exception).__name__}), file=sys.stderr)
        raise SystemExit(1)
