"""
JSON ファイルの入出力に関する関数群

    Last modified: 2025/06/28

    Copyright © 2022 toshifumi tsutsui
    Released under the MIT license
    https://wpandora8.net/the_mit_license.html
"""

import json
from dataclasses import asdict
from typing import Any


def load_dataclass[T](example_dataclass: T, file_path: str) -> T:
    """JSON ファイルからデータを読み込み、指定された datacless のインスタンスに格納して返す。

    Args:
        example_dataclass (T): データを格納して返す dataclass のインスタンスのサンプル（型情報の取得用）。
        file_path (str): JSON ファイルのパス。

    Raises:
        FileNotFoundError: 指定されたファイルが見つからない場合の例外。
        Exception: その他の例外。

    Returns:
        T: 読み込まれたデータが格納された dataclass のインスタンス。
    """

    try:
        with open(file_path, "r") as file:
            data: dict = json.load(file)

    except FileNotFoundError as ex:
        raise ex
    except Exception as ex:
        raise ex
    else:
        return type(example_dataclass)(**data)


def output_dataclass(data: Any, file_path: str) -> None:
    """dataclass のインスタンスに格納されたデータを JSON ファイルに出力する。

    Args:
        data (Any): データが格納された任意の型の dataclass のインスタンス。
        file_path (str): JSON ファイルのパス。

    Raises:
        FileExistsError: 指定されたファイルが既に存在した場合の例外。
        PermissionError: 指定されたファイルへの書き込み権限がない場合の例外。
        Exception: その他の例外。
    """

    try:
        with open(file_path, "w") as file:
            json.dump(asdict(data), file, indent=2)

    except FileExistsError as ex:
        raise ex
    except PermissionError as ex:
        raise ex
    except Exception as ex:
        raise ex


def load_dataclass_list[T](example_dataclass: T, file_path: str) -> list[T]:
    """JSON ファイルからデータを読み込み、指定された datacless のインスタンスに格納したリストを返す。

    Args:
        dataclass (T): データを格納して返す dataclass のインスタンスのサンプル（型情報の取得用）。
        file_path (str): JSON ファイルのパス。

    Raises:
        FileNotFoundError: 指定されたファイルが見つからない場合の例外。
        Exception: その他の例外。

    Returns:
        list[T]: 読み込まれたデータが格納された dataclass のインスタンスのリスト。
    """

    try:
        with open(file_path, "r") as file:
            data: list[dict] = json.load(file)

    except FileNotFoundError as ex:
        raise ex
    except Exception as ex:
        raise ex
    else:
        return [type(example_dataclass)(**d) for d in data]


def output_dataclass_list(data: list[Any], file_path: str) -> None:
    """dataclass のインスタンスのリストに格納されたデータを JSON ファイルに出力する。

    Args:
        data (Any): データが格納された任意の型の dataclass のインスタンスのリスト。
        file_path (str): JSON ファイルのパス。

    Raises:
        FileExistsError: 指定されたファイルが既に存在した場合の例外。
        PermissionError: 指定されたファイルへの書き込み権限がない場合の例外。
        Exception: その他の例外。
    """

    try:
        with open(file_path, "w") as file:
            json.dump([asdict(d) for d in data], file, indent=2)

    except FileExistsError as ex:
        raise ex
    except PermissionError as ex:
        raise ex
    except Exception as ex:
        raise ex
