"""Regal Language Server implementation for Rego policy files."""

import logging
import shutil

from overrides import override

from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.settings import SolidLSPSettings

log = logging.getLogger(__name__)


class RegalLanguageServer(SolidLanguageServer):
    """
    Provides Rego specific instantiation of the LanguageServer class using Regal.

    Regal is the official linter and language server for Rego (Open Policy Agent's policy language).
    See: https://github.com/StyraInc/regal
    """

    @override
    def is_ignored_dirname(self, dirname: str) -> bool:
        return super().is_ignored_dirname(dirname) or dirname in [".regal", ".opa"]

    def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings):
        """
        Creates a RegalLanguageServer instance.

        This class is not meant to be instantiated directly. Use LanguageServer.create() instead.

        :param config: Language server configuration
        :param repository_root_path: Path to the repository root
        :param solidlsp_settings: Settings for solidlsp
        """
        # Regal should be installed system-wide (via CI or user installation)
        regal_executable_path = shutil.which("regal")
        if not regal_executable_path:
            raise RuntimeError(
                "Regal language server not found. Please install it from https://github.com/StyraInc/regal or via your package manager."
            )

        super().__init__(
            config,
            repository_root_path,
            ProcessLaunchInfo(cmd=f"{regal_executable_path} language-server", cwd=repository_root_path),
            "rego",
            solidlsp_settings,
        )

    def _create_base_initialize_params(self) -> dict:
        """
        Returns the initialize params for the Regal Language Server.

        :return: LSP initialization parameters
        """
        initialize_params = {
            "locale": "en",
            "capabilities": {
                "textDocument": {
                    "synchronization": {"didSave": True, "dynamicRegistration": True},
                    "completion": {"dynamicRegistration": True, "completionItem": {"snippetSupport": True}},
                    "definition": {"dynamicRegistration": True},
                    "references": {"dynamicRegistration": True},
                    "documentSymbol": {
                        "dynamicRegistration": True,
                        "hierarchicalDocumentSymbolSupport": True,
                        "symbolKind": {"valueSet": list(range(1, 27))},
                    },
                    "hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
                    "codeAction": {"dynamicRegistration": True},
                    "formatting": {"dynamicRegistration": True},
                },
                "workspace": {
                    "workspaceFolders": True,
                    "didChangeConfiguration": {"dynamicRegistration": True},
                    "symbol": {"dynamicRegistration": True},
                },
            },
        }
        return initialize_params

    def _start_server(self) -> None:
        """Start Regal language server process and wait for initialization."""

        def register_capability_handler(params) -> None:
            return

        def window_log_message(msg) -> None:
            log.info(f"LSP: window/logMessage: {msg}")

        def do_nothing(params) -> None:
            return

        self.server.on_request("client/registerCapability", register_capability_handler)
        self.server.on_notification("window/logMessage", window_log_message)
        self.server.on_notification("$/progress", do_nothing)
        self.server.on_notification("textDocument/publishDiagnostics", do_nothing)

        log.info("Starting Regal language server process")
        self.server.start()
        initialize_params = self._create_initialize_params()

        log.info(
            "Sending initialize request from LSP client to LSP server and awaiting response",
        )
        init_response = self.server.send.initialize(initialize_params)

        # Verify server capabilities
        assert "capabilities" in init_response
        assert "textDocumentSync" in init_response["capabilities"]

        self.server.notify.initialized({})

        # Regal server is ready immediately after initialization
