"""File Service calls."""

from collections.abc import Callable
import json

import voluptuous as vol
import yaml

from homeassistant.core import HomeAssistant, ServiceCall, SupportsResponse, callback
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import config_validation as cv

from .const import ATTR_FILE_ENCODING, ATTR_FILE_NAME, DOMAIN, SERVICE_READ_FILE


@callback
def async_setup_services(hass: HomeAssistant) -> None:
    """Register services for File integration."""

    hass.services.async_register(
        DOMAIN,
        SERVICE_READ_FILE,
        read_file,
        schema=vol.Schema(
            {
                vol.Required(ATTR_FILE_NAME): cv.string,
                vol.Required(ATTR_FILE_ENCODING): cv.string,
            }
        ),
        supports_response=SupportsResponse.ONLY,
    )


ENCODING_LOADERS: dict[str, tuple[Callable, type[Exception]]] = {
    "json": (json.loads, json.JSONDecodeError),
    "yaml": (yaml.safe_load, yaml.YAMLError),
}


def read_file(call: ServiceCall) -> dict:
    """Handle read_file service call."""
    file_name = call.data[ATTR_FILE_NAME]
    file_encoding = call.data[ATTR_FILE_ENCODING].lower()

    if not call.hass.config.is_allowed_path(file_name):
        raise ServiceValidationError(
            translation_domain=DOMAIN,
            translation_key="no_access_to_path",
            translation_placeholders={"filename": file_name},
        )

    if file_encoding not in ENCODING_LOADERS:
        raise ServiceValidationError(
            translation_domain=DOMAIN,
            translation_key="unsupported_file_encoding",
            translation_placeholders={
                "filename": file_name,
                "encoding": file_encoding,
            },
        )

    try:
        with open(file_name, encoding="utf-8") as file:
            file_content = file.read()
    except FileNotFoundError as err:
        raise ServiceValidationError(
            translation_domain=DOMAIN,
            translation_key="file_not_found",
            translation_placeholders={"filename": file_name},
        ) from err
    except OSError as err:
        raise HomeAssistantError(
            translation_domain=DOMAIN,
            translation_key="file_read_error",
            translation_placeholders={"filename": file_name},
        ) from err

    loader, error_type = ENCODING_LOADERS[file_encoding]
    try:
        data = loader(file_content)
    except error_type as err:
        raise HomeAssistantError(
            translation_domain=DOMAIN,
            translation_key="file_decoding",
            translation_placeholders={"filename": file_name, "encoding": file_encoding},
        ) from err

    return {"data": data}
