from __future__ import annotations

import pathlib
import shutil
import yaml
import numpy as np

from .file_utils import safe_open_file
from .path_utils import get_path


def get_chisurf_settings(setting_file: pathlib.Path, use_source_folder: bool = False) -> dict:
    """This function returns the content of a settings file in the user
    settings path. If the settings file does not exist it is copied from
    the package folder to the user settings path.

    :param setting_file: path to settings file
    :param use_source_folder: if true use settings file in source code folder
    :return:
    """
    package_path = pathlib.Path(__file__).parent
    original_settings = package_path / setting_file.parts[-1]
    if use_source_folder:
        setting_file = package_path / setting_file.parts[-1]
    else:
        if not setting_file.is_file():
            shutil.copyfile(original_settings, setting_file)
    return safe_open_file(
        file_path=setting_file,
        processor=yaml.safe_load,
        default_value={},
        error_message=f"Error opening settings file {setting_file}"
    )


def copy_settings_to_user_folder():
    """Copies all settings files from the package directory to the user folder,
    ensuring that existing files are not overwritten."""
    package_path = pathlib.Path(__file__).parent
    user_settings_path = get_path('settings')
    user_settings_path.mkdir(parents=True, exist_ok=True)

    for file in package_path.iterdir():
        if not file.is_file():
            continue
        # Help mappings are considered part of the application resources and are
        # not meant to be edited per-user, so we do not copy help_mappings.yaml
        # into the user settings directory.
        if file.name == "help_mappings.yaml":
            continue
        destination_file = user_settings_path / file.name
        if not destination_file.exists():  # Avoid overwriting existing files
            shutil.copyfile(file, destination_file)

    # Also copy style files
    copy_styles_to_user_folder()


def copy_styles_to_user_folder():
    """Copies all style files from the gui/styles directory to the user folder,
    ensuring that existing files are not overwritten."""
    package_path = pathlib.Path(__file__).parent.parent / 'gui' / 'styles'
    user_settings_path = get_path('settings') / 'styles'
    user_settings_path.mkdir(parents=True, exist_ok=True)

    for file in package_path.iterdir():
        if file.is_file() and file.suffix == '.qss':
            destination_file = user_settings_path / file.name
            if not destination_file.exists():  # Avoid overwriting existing files
                shutil.copyfile(file, destination_file)


def set_warn_missing_detector_setups(show_warning: bool) -> bool:
    """Persist the warn_missing_detector_setups flag in the user's settings YAML.

    Args:
        show_warning: If True, the warning dialog will be shown when the setups file is missing.
                      If False, the warning will be suppressed in the future.
    Returns:
        True if the file was written successfully, False otherwise.
    """
    try:
        settings_file = get_path('settings') / 'settings_chisurf.yaml'
        data = safe_open_file(
            file_path=settings_file,
            processor=yaml.safe_load,
            default_value={},
            error_message=f"Error opening settings file {settings_file}"
        )
        if not isinstance(data, dict):
            data = {}
        data['warn_missing_detector_setups'] = bool(show_warning)
        with open(settings_file, 'w', encoding='utf-8') as fh:
            yaml.safe_dump(data, fh, default_flow_style=False)
        return True
    except Exception:
        return False


def build_fret_rda_axis(
    rda_min: float,
    rda_max: float,
    rda_resolution: int,
    rda_scale: str | None = None,
) -> np.ndarray:
    if rda_resolution < 2:
        rda_resolution = 2
    scale = str(rda_scale or "log").lower()
    try:
        if scale.startswith("lin"):
            axis = np.linspace(
                float(rda_min),
                float(rda_max),
                int(rda_resolution),
                dtype=np.float64,
            )
        else:
            axis = np.logspace(
                start=np.log10(float(rda_min)),
                stop=np.log10(float(rda_max)),
                num=int(rda_resolution),
                dtype=np.float64,
            )
    except Exception:
        try:
            axis = np.linspace(
                float(rda_min),
                float(rda_max),
                int(rda_resolution),
                dtype=np.float64,
            )
        except Exception:
            axis = np.linspace(1.0, 130.0, 96, dtype=np.float64)
    return axis


def set_fret_rda_axis(
    rda_min: float,
    rda_max: float,
    rda_resolution: int,
    rda_scale: str | None = None,
) -> bool:
    """Persist global FRET R_DA axis settings in the user's settings YAML.

    The values are stored under the ``fret`` section as ``rda_min``,
    ``rda_max``, ``rda_resolution`` and optionally ``rda_scale`` ("log" or
    "lin") and are used to build the distance grid for FRET-related models.
    """
    try:
        settings_file = get_path('settings') / 'settings_chisurf.yaml'
        data = safe_open_file(
            file_path=settings_file,
            processor=yaml.safe_load,
            default_value={},
            error_message=f"Error opening settings file {settings_file}"
        )
        if not isinstance(data, dict):
            data = {}
        fret_cfg = data.get('fret')
        if not isinstance(fret_cfg, dict):
            fret_cfg = {}
            data['fret'] = fret_cfg
        fret_cfg['rda_min'] = float(rda_min)
        fret_cfg['rda_max'] = float(rda_max)
        fret_cfg['rda_resolution'] = int(rda_resolution)
        if rda_scale is not None:
            fret_cfg['rda_scale'] = str(rda_scale)
        with open(settings_file, 'w', encoding='utf-8') as fh:
            yaml.safe_dump(data, fh, default_flow_style=False)
        return True
    except Exception:
        return False


def set_check_experiment_config_updates_on_startup(check_updates: bool) -> bool:
    try:
        settings_file = get_path('settings') / 'settings_chisurf.yaml'
        data = safe_open_file(
            file_path=settings_file,
            processor=yaml.safe_load,
            default_value={},
            error_message=f"Error opening settings file {settings_file}"
        )
        if not isinstance(data, dict):
            data = {}
        data['check_experiment_config_updates_on_startup'] = bool(check_updates)
        with open(settings_file, 'w', encoding='utf-8') as fh:
            yaml.safe_dump(data, fh, default_flow_style=False)
        return True
    except Exception:
        return False