#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ***************************************************************************
# * SPDX-FileCopyrightText: 2024 S. MANKOWSKI stephane@mankowski.fr
# * SPDX-FileCopyrightText: 2024 G. DE BURE support@mankowski.fr
# * SPDX-License-Identifier: GPL-3.0-or-later
# ***************************************************************************
import csv
import enum
import locale
import re
import sys
import urllib.parse
import urllib.request
from collections.abc import Generator, Iterable
from contextlib import contextmanager
from dataclasses import dataclass
from datetime import date, datetime
from typing import TextIO

BASE_URL = "http://www.boursorama.com/bourse/action/graph/ws/download"
LOOKUP_URL = "https://www.boursorama.com/recherche/"
SYMBOL_RE = re.compile(r"/cours/([a-zA-Z0-9]+)")
NAVIGATION_RE = re.compile(r"Page \d+")


class Interval(enum.Enum):
    daily = "1d"
    monthly = "1mo"
    weekly = "1wk"


INTERVAL_TO_PERIOD = {Interval.daily: 1, Interval.monthly: 30, Interval.weekly: 7}

# Always ask for 365 entries
MAX_ITEMS = 365
EXPECTED_DATE_FORMAT = "%d/%m/%Y %H:%M"


@dataclass
class TickerValue:
    date: date
    price: float


def ticker_to_url(ticker: str) -> str:
    params = urllib.parse.urlencode(dict(query=ticker))
    request = urllib.request.Request(
        f"{LOOKUP_URL}?{params}",
        headers={
            "Cookie": "_pctx=dummy",
            "User-Agent": "Mozilla/5.0",
        },
    )
    with urllib.request.urlopen(request) as response:
        redirect = response.geturl()

    match = SYMBOL_RE.search(redirect)
    if match is None:
        raise ValueError(
            "Ticker search did not return a valid location: check the symbol"
        )
    actual_code = match.groups()[0]
    return actual_code


def request_one_page(
    interval: Interval,
    symbol: str,
    start_date: date,
) -> str:
    params: dict[str, str | int] = {
        "symbol": symbol,
        # Always ask for at most 365 entries
        "length": MAX_ITEMS,
        "period": INTERVAL_TO_PERIOD[interval],
    }
    query = urllib.parse.urlencode(params)
    request = urllib.request.Request(
        f"{BASE_URL}?{query}",
        headers={
            "Cookie": "_pctx=dummy",
            "User-Agent": "Mozilla/5.0",
        },
    )
    with urllib.request.urlopen(request) as response:
        return response.read().decode("utf8")


def download_history(
    interval: Interval, symbol: str, start_date: date
) -> Generator[TickerValue]:
    response = request_one_page(interval, symbol, start_date)
    csv_reader = csv.reader(response.splitlines(), delimiter="\t")
    for idx, line in enumerate(csv_reader):
        # First line is an header
        if idx == 0:
            continue
        if not line:
            continue
        date = datetime.strptime(line[0], EXPECTED_DATE_FORMAT).date()
        value = float(line[1])
        yield TickerValue(date=date, price=value)


def dump_to_csv(symbol: str, ticker_values: Iterable[TickerValue], output: TextIO):
    writer = csv.writer(output)
    writer.writerow(("date", "price"))
    for value in ticker_values:
        writer.writerow((value.date, value.price))


if __name__ == "__main__":
    symbol = sys.argv[1]
    from_date = date.fromisoformat(sys.argv[2])
    interval = Interval(sys.argv[3])

    actual_symbol = ticker_to_url(symbol)
    results = sorted(
        download_history(interval, actual_symbol, from_date),
        key=lambda x: x.date,
        reverse=True,
    )
    dump_to_csv(symbol, results, sys.stdout)
