import base64
import binascii
import logging
from pathlib import Path

from xdg_base_dirs import xdg_config_home

from griptape_nodes.retained_mode.events.static_file_events import (
    CreateStaticFileRequest,
    CreateStaticFileResultFailure,
    CreateStaticFileResultSuccess,
)
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
from griptape_nodes.retained_mode.managers.event_manager import EventManager

logger = logging.getLogger("griptape_nodes")

USER_CONFIG_PATH = xdg_config_home() / "griptape_nodes" / "griptape_nodes_config.json"


class StaticFilesManager:
    """A class to manage the creation and management of static files."""

    def __init__(self, config_manager: ConfigManager, event_manager: EventManager | None = None) -> None:
        """Initialize the StaticFilesManager.

        Args:
            config_manager: The ConfigManager instance to use for accessing the workspace path.
            event_manager: The EventManager instance to use for event handling.
        """
        self.config_manager = config_manager
        if event_manager is not None:
            event_manager.assign_manager_to_request_type(
                CreateStaticFileRequest, self.on_handle_create_static_file_request
            )

    def on_handle_create_static_file_request(
        self,
        request: CreateStaticFileRequest,
    ) -> CreateStaticFileResultSuccess | CreateStaticFileResultFailure:
        file_name = request.file_name
        try:
            url = self.save_static_file(base64.b64decode(request.content), file_name)
        except binascii.Error:
            msg = f"Invalid base64 encoding for file {file_name}."
            logger.error(msg)
            return CreateStaticFileResultFailure(error=msg)
        except (OSError, PermissionError) as e:
            msg = f"Failed to write file {file_name} to {self.config_manager.workspace_path}: {e}"
            logger.error(msg)
            return CreateStaticFileResultFailure(error=msg)
        except ValueError as e:
            msg = str(e)
            logger.error(msg)
            return CreateStaticFileResultFailure(error=msg)
        else:
            return CreateStaticFileResultSuccess(url=url)

    def save_static_file(self, data: bytes, file_name: str) -> str:
        """Saves a static file to the workspace directory.

        This is used to save files that are generated by the node, such as images or other artifacts.

        Args:
            data: The file data to save.
            file_name: The name of the file to save.

        Returns:
            The URL of the saved file.
        """
        from griptape_nodes.app.app import (
            STATIC_SERVER_ENABLED,
            STATIC_SERVER_HOST,
            STATIC_SERVER_PORT,
            STATIC_SERVER_URL,
        )

        if not STATIC_SERVER_ENABLED:
            msg = "Static server is not enabled. Please set STATIC_SERVER_ENABLED to True."
            raise ValueError(msg)

        file_path = Path(
            self.config_manager.workspace_path / self.config_manager.merged_config["static_files_directory"]
        )
        if not file_path.exists():
            file_path.mkdir(parents=True, exist_ok=True)
        Path(file_path / file_name).write_bytes(data)

        static_url = f"http://{STATIC_SERVER_HOST}:{STATIC_SERVER_PORT}{STATIC_SERVER_URL}/{file_name}"

        return static_url
