from typing import cast

from abstra_internals.controllers.docs import DocsController
from abstra_internals.controllers.git import EmailProvider, GitController
from abstra_internals.controllers.main import MainController
from abstra_internals.controllers.tasks import TasksController
from abstra_internals.controllers.workflows import WorkflowController
from abstra_internals.environment import EDITOR_MODE, EXTERNAL_PLAYER_URL
from abstra_internals.utils.mcp import requires_approval
from abstra_internals.utils.mcp_bp import mcp_bp


def get_editor_bp(main_controller: MainController):
    tasks_controller = TasksController(main_controller.repositories)
    workflow_controller = WorkflowController(main_controller.repositories)
    docs_controller = DocsController(main_controller.repositories)
    git_controller = (
        GitController(email_provider=cast(EmailProvider, main_controller))
        if EDITOR_MODE == "local"
        else GitController()
    )

    # Tools cloud-api serves in-process for external-player web editors (its
    # EditorToolsStore also drops tunneled duplicates), so the pod must stop
    # advertising them under the same signal.
    #
    # SOURCE OF TRUTH for exactly which tools are gated here: cloud-api's
    # services/ai/v2/tools/inProcessEditorToolNames.ts (IN_PROCESS_EDITOR_TOOL_NAMES,
    # groups stageWrite / codebaseRead / configRead / taskWrite). The gated
    # blocks below MUST mirror it — keep them in sync when adding/removing a
    # tool. (Cross-language automation of this check is a documented follow-up.)
    # NOTE: the `git` group exists in the manifest but is NOT gated yet — git AI
    # tools stay on the pod until the flip (see git_tools below, GIT FLIP DEFERRED).
    served_by_cloud_api = EDITOR_MODE == "web" and EXTERNAL_PLAYER_URL

    stage_crud_tools = (
        []
        if served_by_cloud_api
        else [
            main_controller.create_stage,
            requires_approval(main_controller.update_stage),
            requires_approval(main_controller.delete_stage),
        ]
    )

    transition_tools = (
        []
        if served_by_cloud_api
        else [
            workflow_controller.add_transition,
            requires_approval(workflow_controller.delete_transition),
        ]
    )

    workspace_write_tools = (
        []
        if served_by_cloud_api
        else [requires_approval(main_controller.update_workspace)]
    )

    task_write_tools = (
        []
        if served_by_cloud_api
        else [
            tasks_controller.create_task,
            tasks_controller.update_task_status,
            requires_approval(tasks_controller.clear_tasks),
        ]
    )

    docs_tools = (
        []
        if served_by_cloud_api
        else [
            docs_controller.read_abstra_docs,
            docs_controller.get_stage_guide,
            docs_controller.list_all_modules_in_abstra_lib,
            docs_controller.list_objects_in_abstra_module,
            docs_controller.describe_class,
            docs_controller.describe_function,
        ]
    )

    read_tools = (
        []
        if served_by_cloud_api
        else [
            main_controller.list_directory,
            main_controller.find_files_by_pattern,
            main_controller.grep_codebase,
            main_controller.search_file_with_context,
            main_controller.read_file_with_pagination,
            main_controller.read_stage_file_with_pagination,
            main_controller.list_all_stages,
            main_controller.get_stage,
            main_controller.get_workspace,
            workflow_controller.get_workflow_settings,
            main_controller.list_executions,
            main_controller.get_execution_logs,
            main_controller.get_execution_tasks,
            tasks_controller.list_tasks,
        ]
    )

    browser_tools = (
        []
        if served_by_cloud_api
        else [
            requires_approval(main_controller.browser_open_page),
            requires_approval(main_controller.browser_navigate),
            main_controller.browser_list_tabs,
            main_controller.browser_close,
            main_controller.browser_get_page_summary,
            main_controller.browser_get_text,
            main_controller.browser_get_html,
            main_controller.browser_get_console_logs,
            main_controller.browser_get_network_requests,
            main_controller.browser_screenshot,
            requires_approval(main_controller.browser_click),
            requires_approval(main_controller.browser_fill),
            requires_approval(main_controller.browser_execute_javascript),
            main_controller.browser_wait,
        ]
    )

    # GIT FLIP DEFERRED: git tools stay on the pod for now. cloud-api ships the
    # git MECHANISM (WebEditorGitService) + the in-process AI tools code, but they
    # are NOT registered/gated yet — git stays on ONE repo (editor/project/.git)
    # so commit + deploy + panel + AI all agree, until the coherent cloud-api
    # deploy (which needs the cloud-api linter deploy-gate) lands. To flip:
    # restore the gated version below AND re-enable createGitTools in cloud-api's
    # editorTools.ts.
    git_tools = [
        git_controller.get_status,
        git_controller.get_commit_history,
        git_controller.commit_changes,
        requires_approval(git_controller.revert_commit),
    ]
    # git_tools = (
    #     []
    #     if served_by_cloud_api
    #     else [
    #         git_controller.get_status,
    #         git_controller.get_commit_history,
    #         git_controller.commit_changes,
    #         requires_approval(git_controller.revert_commit),
    #     ]
    # )

    return mcp_bp(
        [
            *docs_tools,
            *read_tools,
            main_controller.list_linter_issues,
            *stage_crud_tools,
            *workspace_write_tools,
            *transition_tools,
            requires_approval(main_controller.stop_execution),
            requires_approval(main_controller.run_job),
            requires_approval(main_controller.run_tasklet),
            requires_approval(main_controller.run_hook),
            # run_page is effectively read-only (opens the page headless,
            # collects a snapshot, closes the tab) and the base prompt now
            # mandates it after every Page edit — approval friction here
            # discourages the verification loop. run_page_function stays
            # gated: it invokes an arbitrary registered function, which can
            # mutate data.
            main_controller.run_page,
            requires_approval(main_controller.run_page_function),
            *task_write_tools,
            *browser_tools,
            requires_approval(main_controller.execute_code_snippet),
            requires_approval(main_controller.add_and_install_requirement),
            requires_approval(main_controller.linter_repository.fix_issue_in_codebase),
            *git_tools,
        ]
    )
