import configparser
from pathlib import Path
from typing import Any, Union

class ConfigReader:
    """!
    @brief Handles the parsing and retrieval of application settings from INI files.
    
    This class provides a wrapper around configparser to read settings from a file
    with fallback values and type conversion.
    """

    def __init__(self, config_path: str):
        """!
        @brief Initializes the ConfigReader.

        @param config_path The path to the configuration file.
        @exception FileNotFoundError Raised if the configuration file does not exist.
        """
        self.file_path = Path(config_path)
        if not self.file_path.exists():
            raise FileNotFoundError(f"Configuration file not found: {self.file_path}")

        self._parser = configparser.ConfigParser()
        self._parser.read(self.file_path)

    def _get(self, section: str, key: str, fallback: Any = None) -> str:
        """!
        @brief Internal method to safely get a value from the config parser.

        @param section The section in the INI file.
        @param key The key within the section.
        @param fallback The value to return if the section or key is missing.
        @return The value from the config file or the fallback value.
        """
        try:
            return self._parser.get(section, key)
        except (configparser.NoSectionError, configparser.NoOptionError):
            return fallback

    def get_value(self, section: str, key: str, fallback: Any = None) -> Union[str, Any]:
        """!
        @brief Retrieves a value from the configuration.

        @param section The section in the INI file.
        @param key The key within the section.
        @param fallback The value to return if the section or key is missing.
        @return The value from the config file or the fallback value.
        """
        return self._get(section, key, fallback)

    def get_linear_parameter(self) -> float:
        """!
        @brief Retrieves the linear blending parameter.

        @return The linear parameter as a float. Default is 0.0.
        """
        val = self._get('Parameters', 'linear_parameter', '0.0')
        return float(val)

    def get_image_path(self) -> str:
        """!
        @brief Retrieves the path to the input image.

        @return The image path as a string. Default is empty string.
        """
        return self._get('Parameters', 'image_path', '')

    def get_overlap(self) -> str:
        """!
        @brief Retrieves the overlap value.

        @return The overlap value as a string. Default is '0'.
        """
        return self._get('Parameters', 'overlap', '0')

    def get_blend_mode(self) -> str:
        """!
        @brief Retrieves the blend mode.

        @return The blend mode as a string. Default is 'linear'.
        """
        return self._get('Parameters', 'blend_mode', 'linear')

    def save_config(self) -> None:
        """!
        @brief Saves the current configuration to the file.
        """
        with open(self.file_path, 'w') as configfile:
            self._parser.write(configfile)