from __future__ import annotations

import argparse
import hashlib
import json
import time
import urllib.error
import urllib.request
from pathlib import Path


SOURCES = [
    {
        "name": "energy-monthly-generation.csv",
        "url": "https://www.moeaea.gov.tw/ECW/populace/opendata/wHandOpenData_File.ashx?set_id=171",
        "sha256": "1fefcace69af9fefcda01047aeb0b61109d65b5a51cc3d220ebbf9da90d20359",
    },
    {
        "name": "taipower-generation-purchases.csv",
        "url": "https://service.taipower.com.tw/data/opendata/apply/file/d003005/001.csv",
        "sha256": "3dd42fc6eb3955548f36f881fea1580d573eedefaa186b0a41b11b828af04dde",
    },
    {
        "name": "taipower-emission-factors.csv",
        "url": "https://service.taipower.com.tw/data/opendata/apply/file/d061001/001.csv",
        "sha256": "acbfd597dd8b27dad9ffb186086a1e818356e71edfb742191ab6dfce604e1fc9",
    },
    {
        "name": "2025-electricity-emission-factor.pdf",
        "url": "https://www.moeaea.gov.tw/ecw/populace/content/wHandMenuFile.ashx?file_id=17083&menu_id=27028",
        "sha256": "4a4fa4646c53ef8602878dd65e4879fc72313ded4e345f80644c3cb723b09f1c",
    },
]


def digest(data: bytes) -> str:
    return hashlib.sha256(data).hexdigest()


def fetch(url: str) -> bytes:
    request = urllib.request.Request(url, headers={"User-Agent": "SHWRP-reproducibility/1.0"})
    try:
        with urllib.request.urlopen(request, timeout=45) as response:
            return response.read()
    except urllib.error.HTTPError as error:
        if error.code in {401, 403}:
            raise RuntimeError(f"Access denied for public source ({error.code}); stopped without bypass") from error
        if error.code == 429:
            retry_after = error.headers.get("Retry-After")
            raise RuntimeError(f"Rate limited (429); Retry-After={retry_after!r}; stopped") from error
        raise


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--output", type=Path, default=Path("private-source-cache"))
    args = parser.parse_args()
    output = args.output.resolve()
    output.mkdir(parents=True, exist_ok=True)
    results = []
    for index, source in enumerate(SOURCES):
        if index:
            time.sleep(1)
        data = fetch(source["url"])
        actual = digest(data)
        if actual != source["sha256"]:
            raise RuntimeError(
                f"Source changed for {source['name']}; expected {source['sha256']}, received {actual}. "
                "Review the new official release instead of silently mixing versions."
            )
        target = output / source["name"]
        target.write_bytes(data)
        results.append({"name": source["name"], "bytes": len(data), "sha256": actual})
    print(json.dumps(results, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
