"""Config flow for file integration."""

from copy import deepcopy
import os
from typing import Any

import voluptuous as vol

from homeassistant.config_entries import (
    ConfigEntry,
    ConfigFlow,
    ConfigFlowResult,
    OptionsFlow,
    OptionsFlowWithConfigEntry,
)
from homeassistant.const import (
    CONF_FILE_PATH,
    CONF_FILENAME,
    CONF_NAME,
    CONF_PLATFORM,
    CONF_UNIT_OF_MEASUREMENT,
    CONF_VALUE_TEMPLATE,
    Platform,
)
from homeassistant.core import callback
from homeassistant.helpers.selector import (
    BooleanSelector,
    BooleanSelectorConfig,
    TemplateSelector,
    TemplateSelectorConfig,
    TextSelector,
    TextSelectorConfig,
    TextSelectorType,
)

from .const import CONF_TIMESTAMP, DEFAULT_NAME, DOMAIN

BOOLEAN_SELECTOR = BooleanSelector(BooleanSelectorConfig())
TEMPLATE_SELECTOR = TemplateSelector(TemplateSelectorConfig())
TEXT_SELECTOR = TextSelector(TextSelectorConfig(type=TextSelectorType.TEXT))

FILE_OPTIONS_SCHEMAS = {
    Platform.SENSOR.value: vol.Schema(
        {
            vol.Optional(CONF_VALUE_TEMPLATE): TEMPLATE_SELECTOR,
            vol.Optional(CONF_UNIT_OF_MEASUREMENT): TEXT_SELECTOR,
        }
    ),
    Platform.NOTIFY.value: vol.Schema(
        {
            vol.Optional(CONF_TIMESTAMP, default=False): BOOLEAN_SELECTOR,
        }
    ),
}

FILE_FLOW_SCHEMAS = {
    Platform.SENSOR.value: vol.Schema(
        {
            vol.Required(CONF_FILE_PATH): TEXT_SELECTOR,
        }
    ).extend(FILE_OPTIONS_SCHEMAS[Platform.SENSOR.value].schema),
    Platform.NOTIFY.value: vol.Schema(
        {
            vol.Required(CONF_FILE_PATH): TEXT_SELECTOR,
        }
    ).extend(FILE_OPTIONS_SCHEMAS[Platform.NOTIFY.value].schema),
}


class FileConfigFlowHandler(ConfigFlow, domain=DOMAIN):
    """Handle a file config flow."""

    VERSION = 2

    @staticmethod
    @callback
    def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlow:
        """Get the options flow for this handler."""
        return FileOptionsFlowHandler(config_entry)

    async def validate_file_path(self, file_path: str) -> bool:
        """Ensure the file path is valid."""
        return await self.hass.async_add_executor_job(
            self.hass.config.is_allowed_path, file_path
        )

    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle a flow initiated by the user."""
        return self.async_show_menu(
            step_id="user",
            menu_options=["notify", "sensor"],
        )

    async def _async_handle_step(
        self, platform: str, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle file config flow step."""
        errors: dict[str, str] = {}
        if user_input:
            user_input[CONF_PLATFORM] = platform
            self._async_abort_entries_match(user_input)
            if not await self.validate_file_path(user_input[CONF_FILE_PATH]):
                errors[CONF_FILE_PATH] = "not_allowed"
            else:
                title = f"{DEFAULT_NAME} [{user_input[CONF_FILE_PATH]}]"
                data = deepcopy(user_input)
                options = {}
                for key, value in user_input.items():
                    if key not in (CONF_FILE_PATH, CONF_PLATFORM, CONF_NAME):
                        data.pop(key)
                        options[key] = value
                return self.async_create_entry(data=data, title=title, options=options)

        return self.async_show_form(
            step_id=platform, data_schema=FILE_FLOW_SCHEMAS[platform], errors=errors
        )

    async def async_step_notify(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle file notifier config flow."""
        return await self._async_handle_step(Platform.NOTIFY.value, user_input)

    async def async_step_sensor(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Handle file sensor config flow."""
        return await self._async_handle_step(Platform.SENSOR.value, user_input)

    async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
        """Import `file`` config from configuration.yaml."""
        self._async_abort_entries_match(import_data)
        platform = import_data[CONF_PLATFORM]
        name: str = import_data.get(CONF_NAME, DEFAULT_NAME)
        file_name: str
        if platform == Platform.NOTIFY:
            file_name = import_data.pop(CONF_FILENAME)
            file_path: str = os.path.join(self.hass.config.config_dir, file_name)
            import_data[CONF_FILE_PATH] = file_path
        else:
            file_path = import_data[CONF_FILE_PATH]
        title = f"{name} [{file_path}]"
        data = deepcopy(import_data)
        options = {}
        for key, value in import_data.items():
            if key not in (CONF_FILE_PATH, CONF_PLATFORM, CONF_NAME):
                data.pop(key)
                options[key] = value
        return self.async_create_entry(title=title, data=data, options=options)


class FileOptionsFlowHandler(OptionsFlowWithConfigEntry):
    """Handle File options."""

    async def async_step_init(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Manage File options."""
        if user_input:
            return self.async_create_entry(data=user_input)

        platform = self.config_entry.data[CONF_PLATFORM]
        return self.async_show_form(
            step_id="init",
            data_schema=self.add_suggested_values_to_schema(
                FILE_OPTIONS_SCHEMAS[platform], self.config_entry.options or {}
            ),
        )
