"""Local tool executor that dispatches to MCP tool handlers + built-in tools.

Used by the direct-API fallback path when Claude Code CLI is not installed.
"""

from mcp.types import TextContent

from maeris_mcp.storage.api_store import APIStore
from maeris_mcp.storage.automation_store import SetupAutomationStore
from maeris_mcp.storage.coverage_store import CoverageStore
from maeris_mcp.storage.execution_store import TestExecutionStore
from maeris_mcp.storage.security_store import SecurityScanStore
from maeris_mcp.storage.test_store import TestGenerationStore

from maeris_mcp.tools.api_scan import api_scan_tool, handle_api_scan
from maeris_mcp.tools.api_coverage_tool import check_api_coverage_tool, handle_check_api_coverage
from maeris_mcp.tools.api_flow_tools import (
    create_api_flow_tool, get_api_flows_tool, edit_api_flow_tool,
    delete_api_flow_tool, create_flow_tool, create_api_flow_map_tool,
    get_api_flow_map_tool, add_api_flow_params_tool, get_api_flow_params_tool,
    edit_api_flow_params_tool, delete_api_flow_params_tool,
    handle_create_api_flow, handle_get_api_flows, handle_edit_api_flow,
    handle_delete_api_flow, handle_create_flow, handle_create_api_flow_map,
    handle_get_api_flow_map, handle_add_api_flow_params, handle_get_api_flow_params,
    handle_edit_api_flow_params, handle_delete_api_flow_params,
)
from maeris_mcp.tools.api_security_tools import api_security_scan_tool, handle_api_security_scan
from maeris_mcp.tools.api_tools import (
    clear_stored_apis_tool, get_stored_apis_tool,
    handle_clear_stored_apis, handle_get_stored_apis,
)
from maeris_mcp.tools.app_tools import (
    create_application_tool, switch_application_tool, check_plan_tool,
    get_applications_tool, login_tool, logout_tool, status_tool,
    handle_create_application, handle_switch_application, handle_check_plan,
    handle_get_applications, handle_login, handle_logout, handle_status,
)
from maeris_mcp.tools.assertion_tools import (
    list_assertion_types_tool, add_assertion_tool, get_assertions_tool,
    get_assertions_for_api_tool, update_assertion_tool, delete_assertion_tool,
    generate_assertions_tool,
    handle_list_assertion_types, handle_add_assertion, handle_get_assertions,
    handle_get_assertions_for_api, handle_update_assertion, handle_delete_assertion,
    handle_generate_assertions,
)
from maeris_mcp.tools.automation_setup import handle_setup_automation, setup_automation_tool
from maeris_mcp.tools.collection_tools import (
    list_collections_tool, get_collection_tool, list_subcollections_tool,
    search_collections_tool, get_collection_tree_tool, create_collection_tool,
    rename_collection_tool, delete_collection_tool, copy_collection_tool,
    collection_stats_tool, export_collection_tool, import_collection_tool,
    handle_list_collections, handle_get_collection, handle_list_subcollections,
    handle_search_collections, handle_get_collection_tree, handle_create_collection,
    handle_rename_collection, handle_delete_collection, handle_copy_collection,
    handle_collection_stats, handle_export_collection, handle_import_collection,
)
from maeris_mcp.tools.environment_tools import (
    add_environment_tool, get_environments_tool, edit_environment_tool,
    delete_environment_tool, add_environment_data_tool, get_environment_data_tool,
    update_environment_data_tool, delete_environment_data_tool,
    select_environment_tool, get_current_environment_tool,
    handle_add_environment, handle_get_environments, handle_edit_environment,
    handle_delete_environment, handle_add_environment_data,
    handle_get_environment_data, handle_update_environment_data,
    handle_delete_environment_data, handle_select_environment,
    handle_get_current_environment,
)
from maeris_mcp.tools.maeris_sync import handle_push_to_maeris, push_to_maeris_tool
from maeris_mcp.tools.portal_api_tools import (
    add_api_tool, add_apis_bulk_tool, get_api_tool, list_apis_tool,
    update_api_tool, delete_api_tool, move_api_tool, duplicate_api_tool,
    add_api_param_headers_tool, search_apis_tool, list_apis_in_collection_tool,
    update_api_param_header_tool, delete_api_param_header_tool,
    handle_add_api, handle_add_apis_bulk, handle_get_api, handle_list_apis,
    handle_update_api, handle_delete_api, handle_move_api, handle_duplicate_api,
    handle_add_api_param_headers, handle_search_apis, handle_list_apis_in_collection,
    handle_update_api_param_header, handle_delete_api_param_header,
)
from maeris_mcp.tools.create_apis_for import create_apis_for_tool, handle_create_apis_for
from maeris_mcp.tools.run_api_tools import run_api_tool, handle_run_api
from maeris_mcp.tools.run_collection_tools import run_collection_tool, handle_run_collection
from maeris_mcp.tools.run_flow_tools import run_flow_tool, handle_run_flow
from maeris_mcp.tools.security_scan import (
    clear_security_scans_tool, list_security_checks_tool,
    get_security_scans_tool, security_scan_tool,
    handle_clear_security_scans, handle_list_security_checks,
    handle_get_security_scans, handle_security_scan,
)
from maeris_mcp.tools.setup_automation import setup_api_automation_tool, handle_setup_api_automation
from maeris_mcp.tools.test_execution import run_and_fix_tests_tool, handle_run_and_fix_tests
from maeris_mcp.tools.test_generation import generate_tests_tool, handle_generate_tests
from maeris_mcp.tools.test_management import (
    create_test_folder_tool, delete_test_cases_tool, delete_test_folder_tool,
    edit_test_case_tool, edit_test_step_tool, get_test_case_tool,
    import_test_cases_tool, list_test_cases_tool, list_test_folders_tool,
    run_test_cases_tool, search_test_cases_tool,
    handle_create_test_folder, handle_delete_test_cases, handle_delete_test_folder,
    handle_edit_test_case, handle_edit_test_step, handle_get_test_case,
    handle_import_test_cases, handle_list_test_cases, handle_list_test_folders,
    handle_run_test_cases, handle_search_test_cases,
)
from maeris_mcp.tools.test_push import handle_push_tests_to_maeris, push_tests_to_maeris_tool
from maeris_mcp.tools.ui_automation_setup import handle_setup_ui_automation, setup_ui_automation_tool

from ._builtin_tools import (
    BUILTIN_TOOL_DEFINITIONS,
    BUILTIN_DISPATCH,
    get_allowed_builtin_definitions,
    get_allowed_builtin_dispatch,
)


def _mcp_tool_to_anthropic(tool) -> dict:
    """Convert an MCP Tool object to Anthropic API tool format."""
    return {
        "name": tool.name,
        "description": tool.description or "",
        "input_schema": tool.inputSchema,
    }


class LocalToolExecutor:
    """Executes MCP tools and built-in filesystem tools locally."""

    def __init__(self, cwd: str) -> None:
        self.cwd = cwd

        # Same stores as server.py create_server()
        self.api_store = APIStore()
        self.security_store = SecurityScanStore()
        self.test_store = TestGenerationStore()
        self.exec_store = TestExecutionStore()
        self.automation_store = SetupAutomationStore()
        self.coverage_store = CoverageStore()

        # Load scopes
        from maeris_mcp.auth.scopes import load_maeris_scope, load_codebase_scope
        self._maeris_scope = load_maeris_scope()
        self._codebase_scope = load_codebase_scope()

    def get_tool_definitions(self) -> list[dict]:
        """Return Anthropic-format tool definitions for all available tools."""
        from maeris_mcp.auth.scopes import is_maeris_tool_allowed

        mcp_tools = [
            push_to_maeris_tool(),
            list_security_checks_tool(),
            security_scan_tool(),
            get_security_scans_tool(),
            clear_security_scans_tool(),
            api_scan_tool(),
            generate_tests_tool(),
            run_and_fix_tests_tool(),
            push_tests_to_maeris_tool(),
            setup_ui_automation_tool(),
            list_test_folders_tool(),
            create_test_folder_tool(),
            delete_test_folder_tool(),
            list_test_cases_tool(),
            search_test_cases_tool(),
            get_test_case_tool(),
            edit_test_case_tool(),
            edit_test_step_tool(),
            run_test_cases_tool(),
            delete_test_cases_tool(),
            import_test_cases_tool(),
            list_collections_tool(),
            get_collection_tool(),
            list_subcollections_tool(),
            search_collections_tool(),
            get_collection_tree_tool(),
            create_collection_tool(),
            rename_collection_tool(),
            delete_collection_tool(),
            add_api_tool(),
            add_apis_bulk_tool(),
            get_api_tool(),
            list_apis_tool(),
            update_api_tool(),
            delete_api_tool(),
            move_api_tool(),
            duplicate_api_tool(),
            add_api_param_headers_tool(),
            search_apis_tool(),
            list_apis_in_collection_tool(),
            update_api_param_header_tool(),
            delete_api_param_header_tool(),
            copy_collection_tool(),
            collection_stats_tool(),
            export_collection_tool(),
            import_collection_tool(),
            add_environment_tool(),
            get_environments_tool(),
            edit_environment_tool(),
            delete_environment_tool(),
            add_environment_data_tool(),
            get_environment_data_tool(),
            update_environment_data_tool(),
            delete_environment_data_tool(),
            select_environment_tool(),
            get_current_environment_tool(),
            list_assertion_types_tool(),
            generate_assertions_tool(),
            add_assertion_tool(),
            get_assertions_tool(),
            get_assertions_for_api_tool(),
            update_assertion_tool(),
            delete_assertion_tool(),
            api_security_scan_tool(),
            create_api_flow_tool(),
            get_api_flows_tool(),
            edit_api_flow_tool(),
            delete_api_flow_tool(),
            create_flow_tool(),
            create_api_flow_map_tool(),
            get_api_flow_map_tool(),
            add_api_flow_params_tool(),
            get_api_flow_params_tool(),
            edit_api_flow_params_tool(),
            delete_api_flow_params_tool(),
            run_api_tool(),
            run_collection_tool(),
            run_flow_tool(),
            create_application_tool(),
            switch_application_tool(),
            check_plan_tool(),
            get_applications_tool(),
            login_tool(),
            logout_tool(),
            status_tool(),
            setup_api_automation_tool(),
            setup_automation_tool(),
            check_api_coverage_tool(),
            create_apis_for_tool(),
        ]
        defs = [
            _mcp_tool_to_anthropic(t) for t in mcp_tools
            if is_maeris_tool_allowed(t.name, self._maeris_scope)
        ]
        defs.extend(get_allowed_builtin_definitions(self._codebase_scope))
        return defs

    async def execute(self, name: str, arguments: dict) -> str:
        """Dispatch a tool call and return the result as a string."""
        from maeris_mcp.auth.scopes import is_maeris_tool_allowed, is_builtin_tool_allowed

        # Built-in filesystem tools
        allowed_builtins = get_allowed_builtin_dispatch(self._codebase_scope)
        if name in BUILTIN_DISPATCH:
            if name not in allowed_builtins:
                return (
                    f"Error: tool '{name}' is not allowed under the current codebase scope "
                    f"'{self._codebase_scope}'. Change scope with: "
                    f"maeris app scope --codebase <read|write|execute>"
                )
            return allowed_builtins[name](arguments, self.cwd)

        # MCP tools — check maeris scope first
        if not is_maeris_tool_allowed(name, self._maeris_scope):
            return (
                f"Error: tool '{name}' is not allowed under the current Maeris scope "
                f"'{self._maeris_scope}'. Change scope with: "
                f"maeris app scope --maeris <read|write|full>"
            )

        result = await self._dispatch_mcp(name, arguments)
        if result is None:
            return f"Unknown tool: {name}"

        # Convert list[TextContent] → string
        if isinstance(result, list):
            parts = []
            for item in result:
                if isinstance(item, TextContent):
                    parts.append(item.text)
                elif isinstance(item, dict) and "text" in item:
                    parts.append(item["text"])
                else:
                    parts.append(str(item))
            return "\n".join(parts)
        return str(result)

    async def _dispatch_mcp(self, name: str, arguments: dict):
        """Route to the correct MCP handler. Returns list[TextContent] or None."""
        match name:
            case "push_to_maeris":
                return await handle_push_to_maeris(self.security_store, arguments)
            case "list_security_checks":
                return await handle_list_security_checks(arguments)
            case "security_scan":
                return await handle_security_scan(self.security_store, arguments)
            case "get_security_scans":
                return await handle_get_security_scans(self.security_store, arguments)
            case "clear_security_scans":
                return await handle_clear_security_scans(self.security_store, arguments)
            case "api_scan":
                return await handle_api_scan(self.api_store, arguments)
            case "generate_tests":
                return await handle_generate_tests(self.test_store, arguments)
            case "run_and_fix_tests":
                return await handle_run_and_fix_tests(self.exec_store, self.test_store, arguments)
            case "push_tests_to_maeris":
                return await handle_push_tests_to_maeris(self.test_store, self.exec_store, arguments)
            case "setup_ui_automation":
                return await handle_setup_ui_automation(self.test_store, self.exec_store, arguments)
            case "list_test_folders":
                return await handle_list_test_folders(arguments)
            case "create_test_folder":
                return await handle_create_test_folder(arguments)
            case "delete_test_folder":
                return await handle_delete_test_folder(arguments)
            case "list_test_cases":
                return await handle_list_test_cases(arguments)
            case "search_test_cases":
                return await handle_search_test_cases(arguments)
            case "get_test_case":
                return await handle_get_test_case(arguments)
            case "edit_test_case":
                return await handle_edit_test_case(arguments)
            case "edit_test_step":
                return await handle_edit_test_step(arguments)
            case "run_test_cases":
                return await handle_run_test_cases(arguments)
            case "delete_test_cases":
                return await handle_delete_test_cases(arguments)
            case "import_test_cases":
                return await handle_import_test_cases(arguments)
            case "list_collections":
                return await handle_list_collections(arguments)
            case "get_collection":
                return await handle_get_collection(arguments)
            case "list_subcollections":
                return await handle_list_subcollections(arguments)
            case "search_collections":
                return await handle_search_collections(arguments)
            case "get_collection_tree":
                return await handle_get_collection_tree(arguments)
            case "create_collection":
                return await handle_create_collection(arguments)
            case "rename_collection":
                return await handle_rename_collection(arguments)
            case "delete_collection":
                return await handle_delete_collection(arguments)
            case "add_api":
                return await handle_add_api(arguments)
            case "add_apis_bulk":
                return await handle_add_apis_bulk(arguments)
            case "get_api":
                return await handle_get_api(arguments)
            case "list_apis":
                return await handle_list_apis(arguments)
            case "update_api":
                return await handle_update_api(arguments)
            case "delete_api":
                return await handle_delete_api(arguments)
            case "move_api":
                return await handle_move_api(arguments)
            case "duplicate_api":
                return await handle_duplicate_api(arguments)
            case "add_api_param_headers":
                return await handle_add_api_param_headers(arguments)
            case "search_apis":
                return await handle_search_apis(arguments)
            case "list_apis_in_collection":
                return await handle_list_apis_in_collection(arguments)
            case "update_api_param_header":
                return await handle_update_api_param_header(arguments)
            case "delete_api_param_header":
                return await handle_delete_api_param_header(arguments)
            case "copy_collection":
                return await handle_copy_collection(arguments)
            case "collection_stats":
                return await handle_collection_stats(arguments)
            case "export_collection":
                return await handle_export_collection(arguments)
            case "import_collection":
                return await handle_import_collection(arguments)
            case "add_environment":
                return await handle_add_environment(arguments)
            case "get_environments":
                return await handle_get_environments(arguments)
            case "edit_environment":
                return await handle_edit_environment(arguments)
            case "delete_environment":
                return await handle_delete_environment(arguments)
            case "add_environment_data":
                return await handle_add_environment_data(arguments)
            case "get_environment_data":
                return await handle_get_environment_data(arguments)
            case "update_environment_data":
                return await handle_update_environment_data(arguments)
            case "delete_environment_data":
                return await handle_delete_environment_data(arguments)
            case "select_environment":
                return await handle_select_environment(arguments)
            case "get_current_environment":
                return await handle_get_current_environment(arguments)
            case "list_assertion_types":
                return await handle_list_assertion_types(arguments)
            case "generate_assertions":
                return await handle_generate_assertions(arguments)
            case "add_assertion":
                return await handle_add_assertion(arguments)
            case "get_assertions":
                return await handle_get_assertions(arguments)
            case "get_assertions_for_api":
                return await handle_get_assertions_for_api(arguments)
            case "update_assertion":
                return await handle_update_assertion(arguments)
            case "delete_assertion":
                return await handle_delete_assertion(arguments)
            case "api_security_scan":
                return await handle_api_security_scan(arguments)
            case "create_api_flow":
                return await handle_create_api_flow(arguments)
            case "get_api_flows":
                return await handle_get_api_flows(arguments)
            case "edit_api_flow":
                return await handle_edit_api_flow(arguments)
            case "delete_api_flow":
                return await handle_delete_api_flow(arguments)
            case "create_flow":
                return await handle_create_flow(arguments)
            case "create_api_flow_map":
                return await handle_create_api_flow_map(arguments)
            case "get_api_flow_map":
                return await handle_get_api_flow_map(arguments)
            case "add_api_flow_params":
                return await handle_add_api_flow_params(arguments)
            case "get_api_flow_params":
                return await handle_get_api_flow_params(arguments)
            case "edit_api_flow_params":
                return await handle_edit_api_flow_params(arguments)
            case "delete_api_flow_params":
                return await handle_delete_api_flow_params(arguments)
            case "run_api":
                return await handle_run_api(arguments)
            case "run_collection":
                return await handle_run_collection(arguments)
            case "run_flow":
                return await handle_run_flow(arguments)
            case "setup_automation":
                return await handle_setup_automation(
                    self.test_store, self.api_store,
                    self.security_store, self.exec_store, arguments,
                )
            case "create_application":
                return await handle_create_application(arguments)
            case "switch_application":
                return await handle_switch_application(arguments)
            case "check_plan":
                return await handle_check_plan(arguments)
            case "get_applications":
                return await handle_get_applications(arguments)
            case "login":
                return await handle_login(arguments)
            case "logout":
                return await handle_logout(arguments)
            case "maeris_status":
                return await handle_status(arguments)
            case "setup_api_automation":
                return await handle_setup_api_automation(self.automation_store, arguments)
            case "check_api_coverage":
                return await handle_check_api_coverage(self.coverage_store, arguments)
            case "create_apis_for":
                return await handle_create_apis_for(self.api_store, arguments)
            case _:
                return None
