import { describe, it, expect, vi, beforeEach } from "vitest";
import {
  render,
  screen,
  fireEvent,
  waitFor,
  act,
  within,
} from "@testing-library/react";
import { Integrations } from "./Integrations";
import { useConfigStore } from "@/store/configStore";
import type { AgentPoliciesByAgent } from "@/types/config";

// Mock hooks
const mockTools = [
  {
    name: "weather",
    display_name: "Weather",
    description: "Get weather information",
    icon: "🌤️",
    icon_color: null,
    category: "information",
    status: "available",
    setup_type: "api_key",
    config_fields: [
      {
        name: "WEATHER_API_KEY",
        label: "API Key",
        type: "password",
        required: true,
        placeholder: "Enter your weather API key",
        description: "Your weather service API key",
      },
    ],
    helper_text: null,
    docs_url: null,
    dependencies: null,
  },
];
const scopedMockTools = [
  {
    name: "private_mail",
    display_name: "Private Mail",
    description: "Private scoped mail integration",
    icon: "📫",
    icon_color: null,
    category: "communication",
    status: "available",
    setup_type: "api_key",
    config_fields: [
      {
        name: "PRIVATE_MAIL_API_KEY",
        label: "API Key",
        type: "password",
        required: true,
        placeholder: "Enter your private mail API key",
        description: "Scoped API key",
      },
    ],
    helper_text: null,
    docs_url: null,
    dependencies: null,
  },
];
let mockStatusAuthoritative = true;
const {
  mockUseTools,
  mockGoogleDriveOnAction,
  mockGoogleDriveOnDisconnect,
  mockGoogleGmailOnAction,
  mockGoogleGmailOnDisconnect,
  mockSpotifyOnAction,
  mockSpotifyOnDisconnect,
  mockPlexOnAction,
  mockPlexOnDisconnect,
  mockGenericOAuthOnAction,
  mockGenericOAuthLoadStatus,
  mockGoogleDriveLoadStatus,
  mockGoogleGmailLoadStatus,
  mockSpotifyLoadStatus,
  mockPlexLoadStatus,
  mockEnhancedConfigDialogProps,
} = vi.hoisted(() => ({
  mockUseTools: vi.fn(),
  mockGoogleDriveOnAction: vi.fn(),
  mockGoogleDriveOnDisconnect: vi.fn(),
  mockGoogleGmailOnAction: vi.fn(),
  mockGoogleGmailOnDisconnect: vi.fn(),
  mockSpotifyOnAction: vi.fn(),
  mockSpotifyOnDisconnect: vi.fn(),
  mockPlexOnAction: vi.fn(),
  mockPlexOnDisconnect: vi.fn(),
  mockGenericOAuthOnAction: vi.fn(),
  mockGenericOAuthLoadStatus: vi
    .fn()
    .mockResolvedValue({ status: "available", connected: false }),
  mockGoogleDriveLoadStatus: vi
    .fn()
    .mockResolvedValue({ status: "available", connected: false }),
  mockGoogleGmailLoadStatus: vi
    .fn()
    .mockResolvedValue({ status: "available", connected: false }),
  mockSpotifyLoadStatus: vi
    .fn()
    .mockResolvedValue({ status: "available", connected: false }),
  mockPlexLoadStatus: vi
    .fn()
    .mockResolvedValue({ status: "connected", connected: true }),
  mockEnhancedConfigDialogProps: vi.fn(),
}));

function createDeferred() {
  let resolve: () => void = () => undefined;
  const promise = new Promise<void>((promiseResolve) => {
    resolve = () => promiseResolve();
  });
  return { promise, resolve };
}

function makeAgentPolicy(
  agentName: string,
  overrides: Partial<AgentPoliciesByAgent[string]> = {},
): AgentPoliciesByAgent[string] {
  return {
    agent_name: agentName,
    is_private: false,
    effective_execution_scope: null,
    scope_label: "unscoped",
    scope_source: "unscoped",
    dashboard_credentials_supported: true,
    team_eligibility_reason: null,
    private_knowledge_base_id: null,
    private_workspace_enabled: false,
    private_agent_knowledge_enabled: false,
    ...overrides,
  };
}

vi.mock("@/hooks/useTools", () => ({
  useTools: mockUseTools,
  mapToolToIntegration: (tool: any) => ({
    id: tool.name,
    name: tool.display_name,
    description: tool.description,
    category: tool.category,
    status: tool.status,
    setup_type: tool.setup_type,
    config_fields: tool.config_fields,
    helper_text: tool.helper_text,
    docs_url: tool.docs_url,
  }),
}));

// Mock toast
const mockToast = vi.fn();
vi.mock("@/components/ui/use-toast", () => ({
  useToast: () => ({ toast: mockToast }),
}));

// Mock icon mapping
vi.mock("./iconMapping", () => ({
  getIconForTool: (icon: string | null, _iconColor?: string | null) => (
    <span>{icon}</span>
  ),
}));

// Mock API base URL
vi.mock("@/lib/api", () => ({
  API_BASE_URL: "http://localhost:8080",
  withAgentExecutionScope: (url: string) => url,
}));

// Mock EnhancedConfigDialog
vi.mock("./EnhancedConfigDialog", () => ({
  EnhancedConfigDialog: ({ configFields, onSuccess, service }: any) => {
    mockEnhancedConfigDialogProps({ configFields, service });
    // Auto-call success when dialog opens
    setTimeout(() => onSuccess?.(), 0);
    return (
      <>
        <div>Enhanced Config Dialog</div>
        <div>Service: {service}</div>
        <div>Fields: {JSON.stringify(configFields)}</div>
      </>
    );
  },
}));

// Mock integration providers
vi.mock("./integrations/index", () => ({
  GenericOAuthIntegrationProvider: class {
    integration: any;
    providerId: string;

    constructor(integration: any, providerId: string) {
      this.integration = integration;
      this.providerId = providerId;
    }

    getConfig() {
      return {
        integration: this.integration,
        onAction: () => mockGenericOAuthOnAction(this.providerId),
      };
    }

    loadStatus() {
      return mockGenericOAuthLoadStatus(this.providerId);
    }
  },
  integrationProviders: {
    google_drive: {
      getConfig: () => ({
        integration: {
          id: "google_drive",
          name: "Google Drive",
          description:
            "Search, read, upload, and organize files in your connected Google Drive",
          category: "productivity",
          icon: <span>Google Drive Icon</span>,
          status: "available",
          setup_type: "oauth",
          connected: false,
        },
        onAction: mockGoogleDriveOnAction,
        onDisconnect: mockGoogleDriveOnDisconnect,
      }),
      loadStatus: mockGoogleDriveLoadStatus,
    },
    google_gmail: {
      getConfig: () => ({
        integration: {
          id: "google_gmail",
          name: "Gmail",
          description: "Read, search, and manage Gmail emails",
          category: "email",
          icon: <span>Gmail Icon</span>,
          status: "available",
          setup_type: "oauth",
          connected: false,
        },
        onAction: mockGoogleGmailOnAction,
        onDisconnect: mockGoogleGmailOnDisconnect,
      }),
      loadStatus: mockGoogleGmailLoadStatus,
    },
    spotify: {
      getConfig: () => ({
        integration: {
          id: "spotify",
          name: "Spotify",
          description: "Music streaming service",
          category: "entertainment",
          icon: <span>Spotify Icon</span>,
          status: "available",
          setup_type: "oauth",
          connected: false,
        },
        onAction: mockSpotifyOnAction,
        onDisconnect: mockSpotifyOnDisconnect,
      }),
      loadStatus: mockSpotifyLoadStatus,
    },
    plex: {
      getConfig: () => ({
        integration: {
          id: "plex",
          name: "Plex",
          description: "Movie and TV show database",
          category: "entertainment",
          icon: <span>Plex Icon</span>,
          status: "connected",
          setup_type: "api_key",
          connected: true,
        },
        onAction: mockPlexOnAction,
        onDisconnect: mockPlexOnDisconnect,
        ConfigComponent: () => <div>Plex Config Component</div>,
      }),
      loadStatus: mockPlexLoadStatus,
    },
  },
  getAllIntegrations: () => [
    {
      getConfig: () => ({
        integration: {
          id: "google_drive",
          name: "Google Drive",
          description:
            "Search, read, upload, and organize files in your connected Google Drive",
          category: "productivity",
          icon: <span>Google Drive Icon</span>,
          status: "available",
          setup_type: "oauth",
          connected: false,
        },
        onAction: mockGoogleDriveOnAction,
        onDisconnect: mockGoogleDriveOnDisconnect,
      }),
      loadStatus: mockGoogleDriveLoadStatus,
    },
    {
      getConfig: () => ({
        integration: {
          id: "google_gmail",
          name: "Gmail",
          description: "Read, search, and manage Gmail emails",
          category: "email",
          icon: <span>Gmail Icon</span>,
          status: "available",
          setup_type: "oauth",
          connected: false,
        },
        onAction: mockGoogleGmailOnAction,
        onDisconnect: mockGoogleGmailOnDisconnect,
      }),
      loadStatus: mockGoogleGmailLoadStatus,
    },
    {
      getConfig: () => ({
        integration: {
          id: "spotify",
          name: "Spotify",
          description: "Music streaming service",
          category: "entertainment",
          icon: <span>Spotify Icon</span>,
          status: "available",
          setup_type: "oauth",
          connected: false,
        },
        onAction: mockSpotifyOnAction,
        onDisconnect: mockSpotifyOnDisconnect,
      }),
      loadStatus: mockSpotifyLoadStatus,
    },
    {
      getConfig: () => ({
        integration: {
          id: "plex",
          name: "Plex",
          description: "Movie and TV show database",
          category: "entertainment",
          icon: <span>Plex Icon</span>,
          status: "connected",
          setup_type: "api_key",
          connected: true,
        },
        onAction: mockPlexOnAction,
        onDisconnect: mockPlexOnDisconnect,
        ConfigComponent: () => <div>Plex Config Component</div>,
      }),
      loadStatus: mockPlexLoadStatus,
    },
  ],
}));

describe("Integrations", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockToast.mockReset();
    mockStatusAuthoritative = true;
    mockGoogleDriveOnAction.mockResolvedValue(undefined);
    mockGoogleDriveOnDisconnect.mockResolvedValue(undefined);
    mockGoogleGmailOnAction.mockResolvedValue(undefined);
    mockGoogleGmailOnDisconnect.mockResolvedValue(undefined);
    mockSpotifyOnAction.mockResolvedValue(undefined);
    mockSpotifyOnDisconnect.mockResolvedValue(undefined);
    mockPlexOnAction.mockResolvedValue(undefined);
    mockPlexOnDisconnect.mockResolvedValue(undefined);
    mockGenericOAuthOnAction.mockResolvedValue(undefined);
    mockEnhancedConfigDialogProps.mockClear();
    mockGenericOAuthLoadStatus.mockResolvedValue({
      status: "available",
      connected: false,
    });
    mockGoogleDriveLoadStatus.mockResolvedValue({
      status: "available",
      connected: false,
    });
    mockGoogleGmailLoadStatus.mockResolvedValue({
      status: "available",
      connected: false,
    });
    mockSpotifyLoadStatus.mockResolvedValue({
      status: "available",
      connected: false,
    });
    mockPlexLoadStatus.mockResolvedValue({
      status: "connected",
      connected: true,
    });
    mockUseTools.mockImplementation(
      (agentName?: string | null, executionScope?: string | null) => ({
        tools:
          agentName === "mind" && executionScope === "user"
            ? scopedMockTools
            : mockTools,
        loading: false,
        refetch: vi.fn(),
        statusAuthoritative: mockStatusAuthoritative,
      }),
    );
    useConfigStore.setState({ agents: [], agentPoliciesByAgent: {} });
    Object.defineProperty(HTMLElement.prototype, "hasPointerCapture", {
      configurable: true,
      value: () => false,
    });
  });

  it("should render integrations list", async () => {
    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Tools")).toBeInTheDocument();
      expect(
        screen.getByText(
          "Connect external services to enable agent capabilities",
        ),
      ).toBeInTheDocument();
    });
  });

  it("discloses Google data handling before connection", async () => {
    render(<Integrations />);

    await waitFor(() => {
      expect(
        screen.getAllByText(
          /By connecting, you authorize this MindRoom installation/,
        ).length,
      ).toBeGreaterThan(0);
      expect(
        screen.getAllByText(
          /Project maintainers have no automatic access merely because they maintain MindRoom; if they also operate this installation, they may have operator access/,
        ).length,
      ).toBeGreaterThan(0);
      expect(
        screen.getAllByText(
          /The installation operator and anyone with administrative or filesystem access may be able to access stored credentials and data/,
        ).length,
      ).toBeGreaterThan(0);
      expect(
        screen.getAllByText(
          /Shared or unscoped agents can use the connected account for any user authorized to invoke them/,
        ).length,
      ).toBeGreaterThan(0);
    });
    for (const link of screen.getAllByRole("link", {
      name: "Privacy policy",
    })) {
      expect(link).toHaveAttribute(
        "href",
        "https://docs.mindroom.chat/privacy/",
      );
    }
  });

  it("discloses data handling for dynamically registered Google OAuth providers", async () => {
    mockUseTools.mockReturnValue({
      tools: [
        ...mockTools,
        {
          name: "google_tasks_tool",
          display_name: "Google Tasks Tool",
          description: "Manage Google Tasks",
          icon: "✅",
          icon_color: null,
          category: "productivity",
          status: "available",
          setup_type: "oauth",
          config_fields: null,
          helper_text: null,
          docs_url: null,
          dependencies: null,
          auth_provider: "google_tasks",
        },
      ],
      loading: false,
      refetch: vi.fn(),
      statusAuthoritative: true,
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Google Tasks")).toBeInTheDocument();
      expect(
        screen.getAllByText(
          /Project maintainers have no automatic access merely because they maintain MindRoom/,
        ),
      ).toHaveLength(3);
    });
  });

  it("should display all integration cards", async () => {
    render(<Integrations />);

    await waitFor(() => {
      // Provider integrations
      expect(screen.getByText("Google Drive")).toBeInTheDocument();
      expect(
        screen.getByText(
          "Search, read, upload, and organize files in your connected Google Drive",
        ),
      ).toBeInTheDocument();
      expect(screen.getByText("Spotify")).toBeInTheDocument();
      expect(screen.getByText("Music streaming service")).toBeInTheDocument();
      expect(screen.getByText("Plex")).toBeInTheDocument();
      expect(
        screen.getByText("Movie and TV show database"),
      ).toBeInTheDocument();

      // Backend tools
      expect(screen.getByText("Weather")).toBeInTheDocument();
      expect(screen.getByText("Get weather information")).toBeInTheDocument();
    });
  });

  it("should show correct status badges", async () => {
    render(<Integrations />);

    await waitFor(() => {
      // Available integrations (Google Drive, Spotify, and Weather)
      const availableBadges = screen.getAllByText("Available");
      expect(availableBadges.length).toBeGreaterThanOrEqual(2); // At least Google Drive and Spotify

      // Connected integration
      expect(screen.getByText("Connected")).toBeInTheDocument(); // Plex
    });
  });

  it("shows OAuth status errors without client-config wording", async () => {
    mockGoogleDriveLoadStatus.mockResolvedValueOnce({
      status: "not_connected",
      connected: false,
      oauth_client_configured: false,
      status_error: "Requester binding failed.",
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(
        screen.getByText("Status error: Requester binding failed."),
      ).toBeInTheDocument();
      expect(screen.getByText("Status error")).toBeInTheDocument();
      expect(
        screen.getByRole("button", { name: "Retry status" }),
      ).toBeInTheDocument();
      expect(screen.queryByText("Needs client config")).not.toBeInTheDocument();
    });
  });

  it("opens OAuth client config dialog when client config is missing", async () => {
    mockGoogleDriveLoadStatus.mockResolvedValueOnce({
      status: "not_connected",
      connected: false,
      oauth_client_configured: false,
      oauth_client_config_service: "google_drive_oauth_client",
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(
        screen.getByRole("button", { name: "Configure client" }),
      ).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: "Configure client" }));

    await waitFor(() => {
      expect(screen.getByText("Enhanced Config Dialog")).toBeInTheDocument();
      expect(
        screen.getByText("Service: google_drive_oauth_client"),
      ).toBeInTheDocument();
      expect(screen.getByText(/"name":"client_secret"/)).toHaveTextContent(
        /"required":true/,
      );
    });
  });

  it("opens OAuth client config dialog for existing client config", async () => {
    mockGoogleDriveLoadStatus.mockResolvedValueOnce({
      status: "not_connected",
      connected: false,
      oauth_client_configured: true,
      oauth_custom_client_configured: true,
      oauth_client_config_service: "google_drive_oauth_client",
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(
        screen.getByRole("button", { name: "Edit client" }),
      ).toBeInTheDocument();
      expect(
        screen.getAllByRole("button", { name: "Connect" }).length,
      ).toBeGreaterThan(0);
    });

    fireEvent.click(screen.getByRole("button", { name: "Edit client" }));

    await waitFor(() => {
      expect(screen.getByText("Enhanced Config Dialog")).toBeInTheDocument();
      expect(
        screen.getByText("Service: google_drive_oauth_client"),
      ).toBeInTheDocument();
      expect(screen.getByText(/"name":"client_secret"/)).toHaveTextContent(
        /"required":false/,
      );
      expect(screen.getByText(/"name":"client_secret"/)).toHaveTextContent(
        /"requiredWhenFieldChanges":"client_id"/,
      );
      expect(screen.getByText(/"name":"client_secret"/)).toHaveTextContent(
        /Required when changing Client ID/,
      );
      expect(screen.getByText(/"name":"client_secret"/)).toHaveTextContent(
        /The saved secret is kept for edits that do not change the Client ID/,
      );
    });
  });

  it("omits redirect URI from shared OAuth client config dialog", async () => {
    mockGoogleDriveLoadStatus.mockResolvedValueOnce({
      status: "not_connected",
      connected: false,
      oauth_client_configured: true,
      oauth_custom_client_configured: true,
      oauth_client_config_service: "google_oauth_client",
      oauth_client_redirect_uri_supported: false,
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(
        screen.getByRole("button", { name: "Edit client" }),
      ).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: "Edit client" }));

    await waitFor(() => {
      expect(mockEnhancedConfigDialogProps).toHaveBeenCalledWith(
        expect.objectContaining({
          service: "google_oauth_client",
          configFields: [
            expect.objectContaining({ name: "client_id" }),
            expect.objectContaining({ name: "client_secret" }),
          ],
        }),
      );
      const dialogCalls = mockEnhancedConfigDialogProps.mock.calls;
      expect(dialogCalls[dialogCalls.length - 1]?.[0].configFields).not.toEqual(
        expect.arrayContaining([
          expect.objectContaining({ name: "redirect_uri" }),
        ]),
      );
    });
  });

  it("offers a custom client without blocking provisioned OAuth", async () => {
    mockGoogleDriveLoadStatus.mockResolvedValueOnce({
      status: "available",
      connected: false,
      oauth_client_configured: true,
      oauth_custom_client_configured: false,
      oauth_client_config_service: "google_drive_oauth_client",
      oauth_client_redirect_uri_supported: true,
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(
        screen.getAllByRole("button", { name: "Connect" }).length,
      ).toBeGreaterThan(0);
      expect(
        screen.getByRole("button", { name: "Use custom client" }),
      ).toBeInTheDocument();
      expect(
        screen.queryByRole("button", { name: "Configure client" }),
      ).not.toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: "Use custom client" }));

    await waitFor(() => {
      expect(screen.getByText(/"name":"client_secret"/)).toHaveTextContent(
        /"required":true/,
      );
      expect(mockEnhancedConfigDialogProps).toHaveBeenCalledWith(
        expect.objectContaining({
          service: "google_drive_oauth_client",
          configFields: expect.arrayContaining([
            expect.objectContaining({ name: "redirect_uri" }),
          ]),
        }),
      );
    });
  });

  it("uses the API origin for OAuth client redirect URI placeholders", async () => {
    mockGoogleDriveLoadStatus.mockResolvedValueOnce({
      status: "not_connected",
      connected: false,
      oauth_client_configured: false,
      oauth_client_config_service: "google_drive_oauth_client",
      oauth_client_redirect_uri_supported: true,
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(
        screen.getByRole("button", { name: "Configure client" }),
      ).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole("button", { name: "Configure client" }));

    await waitFor(() => {
      const dialogCalls = mockEnhancedConfigDialogProps.mock.calls;
      const configFields =
        dialogCalls[dialogCalls.length - 1]?.[0].configFields;

      expect(configFields).toEqual(
        expect.arrayContaining([
          expect.objectContaining({
            name: "redirect_uri",
            placeholder:
              "http://localhost:8080/api/oauth/google_drive/callback",
          }),
        ]),
      );
    });
  });

  it("should filter integrations by search term", async () => {
    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Google Drive")).toBeInTheDocument();
    });

    const searchInput = screen.getByPlaceholderText("Search tools...");
    fireEvent.change(searchInput, { target: { value: "spotify" } });

    await waitFor(() => {
      expect(screen.getByText("Spotify")).toBeInTheDocument();
      expect(screen.queryByText("Google Drive")).not.toBeInTheDocument();
      expect(screen.queryByText("Plex")).not.toBeInTheDocument();
    });
  });

  it("should filter by availability", async () => {
    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Weather")).toBeInTheDocument();
    });

    // Click "Available" filter button
    const availableButton = screen.getByRole("button", { name: "Available" });
    fireEvent.click(availableButton);

    await waitFor(() => {
      expect(screen.getByText("Google Drive")).toBeInTheDocument(); // Available
    });
  });

  it("should display category tabs", async () => {
    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByRole("tab", { name: /All/ })).toBeInTheDocument();
      expect(
        screen.getByRole("tab", { name: /Email & Calendar/ }),
      ).toBeInTheDocument();
      expect(
        screen.getByRole("tab", { name: /Entertainment/ }),
      ).toBeInTheDocument();
      expect(
        screen.getByRole("tab", { name: /Information/ }),
      ).toBeInTheDocument();
    });
  });

  it("uses wrapping layout classes for narrow viewports", async () => {
    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Tools")).toBeInTheDocument();
    });

    const headerRow = screen.getByText("Tools").parentElement;
    expect(headerRow).toHaveClass("flex-wrap");

    const scopeSelector = screen.getByRole("combobox");
    expect(scopeSelector).toHaveClass("w-full", "sm:w-72");

    const controlsRow = scopeSelector.parentElement;
    expect(controlsRow).toHaveClass("flex-wrap", "w-full");

    const searchInput = screen.getByPlaceholderText("Search tools...");
    expect(searchInput).toHaveClass("w-full", "sm:w-64");

    const tabList = screen.getByRole("tablist");
    expect(tabList).toHaveClass("flex-wrap", "h-auto", "overflow-visible");
  });

  it.skip("should filter by category when tab is clicked", async () => {
    // TODO: Fix tab panel visibility testing
    render(<Integrations />);

    // Wait for initial render
    await waitFor(() => {
      expect(screen.getByText("Google Drive")).toBeInTheDocument();
      expect(screen.getByText("Spotify")).toBeInTheDocument();
    });

    // Click Entertainment tab
    const entertainmentTab = screen.getByRole("tab", { name: /Entertainment/ });
    fireEvent.click(entertainmentTab);

    // Wait a bit for tab content to change
    await waitFor(() => {
      // In Entertainment category, we should see Spotify and Plex
      expect(screen.getByText("Spotify")).toBeInTheDocument();
      expect(screen.getByText("Plex")).toBeInTheDocument();
    });

    // Since tabs hide other content, these should not be visible
    // But the elements might still be in the DOM, just hidden
    // So let's check for visibility instead
    const googleElement = screen.queryByText(
      "Search, read, upload, and organize files in your connected Google Drive",
    );
    if (googleElement) {
      // Check if it's hidden (parent tab panel might be hidden)
      const tabPanel = googleElement.closest('[role="tabpanel"]');
      if (tabPanel) {
        expect(tabPanel).toHaveAttribute("hidden");
      }
    }
  });

  it("should show correct action buttons", async () => {
    render(<Integrations />);

    await waitFor(() => {
      // OAuth type
      const connectButtons = screen.getAllByRole("button", { name: /Connect/ });
      expect(connectButtons.length).toBeGreaterThan(0);

      // Connected integration
      const disconnectButtons = screen.getAllByRole("button", {
        name: /Disconnect/,
      });
      expect(disconnectButtons.length).toBeGreaterThan(0);
    });
  });

  it("should show config dialog for tools with config fields", async () => {
    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Weather")).toBeInTheDocument();
    });

    // Find the Weather card and its Configure button
    const weatherCard = screen.getByText("Weather").closest(".h-full");
    const configureButton = weatherCard?.querySelector("button:not(:disabled)");

    if (configureButton) {
      fireEvent.click(configureButton);

      await waitFor(() => {
        // Should show the Enhanced Config Dialog
        expect(screen.getByText("Enhanced Config Dialog")).toBeInTheDocument();
      });
    }
  });

  it("should handle disconnect action", async () => {
    // Mock the fetch API
    global.fetch = vi.fn().mockResolvedValue({
      ok: true,
      json: async () => ({}),
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Plex")).toBeInTheDocument();
    });

    // Find and click the Plex Disconnect button
    const imdbCard = screen.getByText("Plex").closest(".h-full");
    const disconnectButton = imdbCard?.querySelector(
      'button[class*="destructive"]',
    );

    if (disconnectButton) {
      fireEvent.click(disconnectButton);

      await waitFor(() => {
        expect(mockToast).toHaveBeenCalledWith({
          title: "Disconnected",
          description: "Plex has been disconnected.",
        });
      });
    }
  });

  it("lists worker-scoped and private agents in the scope selector", async () => {
    useConfigStore.setState({
      agents: [
        {
          id: "general",
          display_name: "Unscoped Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["lobby"],
          worker_scope: null,
        },
        {
          id: "code",
          display_name: "Scoped Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["lobby"],
          worker_scope: "shared",
        },
        {
          id: "mind",
          display_name: "Private Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["personal"],
          private: {
            per: "user_agent",
          },
        },
      ],
      agentPoliciesByAgent: {
        general: makeAgentPolicy("general"),
        code: makeAgentPolicy("code", {
          effective_execution_scope: "shared",
          scope_label: "worker_scope=shared",
          scope_source: "agent.worker_scope",
        }),
        mind: makeAgentPolicy("mind", {
          is_private: true,
          effective_execution_scope: "user_agent",
          scope_label: "private.per=user_agent",
          scope_source: "private.per",
          dashboard_credentials_supported: false,
          private_workspace_enabled: true,
        }),
      },
    });

    render(<Integrations />);

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });

    await waitFor(() => {
      expect(screen.getByText("Scoped Agent")).toBeInTheDocument();
      expect(screen.getByText("Private Agent")).toBeInTheDocument();
    });

    expect(screen.queryByText("Unscoped Agent")).not.toBeInTheDocument();
  });

  it("treats defaults.worker_scope as inherited execution scope in the selector", async () => {
    useConfigStore.setState({
      agents: [
        {
          id: "general",
          display_name: "Inherited Scope Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["lobby"],
          worker_scope: null,
        },
      ],
      agentPoliciesByAgent: {
        general: makeAgentPolicy("general", {
          effective_execution_scope: "user",
          scope_label: "worker_scope=user",
          scope_source: "defaults.worker_scope",
          dashboard_credentials_supported: false,
        }),
      },
      config: {
        memory: {
          backend: "mem0",
          embedder: {
            provider: "openai",
            config: { model: "text-embedding-3-small" },
          },
        },
        models: {
          default: { provider: "test", id: "test-model" },
        },
        agents: {
          general: {
            display_name: "Inherited Scope Agent",
            role: "test",
            tools: ["gmail"],
            skills: [],
            instructions: [],
            rooms: ["lobby"],
          },
        },
        defaults: {
          markdown: true,
          worker_scope: "user",
        },
        router: {
          model: "default",
        },
      },
    });

    render(<Integrations />);

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });

    await waitFor(() => {
      expect(screen.getByText("Inherited Scope Agent")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText("Inherited Scope Agent"));

    await waitFor(() => {
      expect(
        screen.getByText(
          "Configuring tools for Inherited Scope Agent (worker_scope=user).",
        ),
      ).toBeInTheDocument();
    });
  });

  it("shows requester-scoped status as preview only", async () => {
    mockStatusAuthoritative = false;
    useConfigStore.setState({
      agents: [
        {
          id: "mind",
          display_name: "Private Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["personal"],
          private: {
            per: "user",
          },
        },
      ],
      agentPoliciesByAgent: {
        mind: makeAgentPolicy("mind", {
          is_private: true,
          effective_execution_scope: "user",
          scope_label: "private.per=user",
          scope_source: "private.per",
          dashboard_credentials_supported: false,
          private_workspace_enabled: true,
        }),
      },
    });

    render(<Integrations />);

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });

    await waitFor(() => {
      expect(screen.getByText("Private Agent")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText("Private Agent"));

    await waitFor(() => {
      expect(
        screen.getByText(/Requester-scoped tool status is preview only/i),
      ).toBeInTheDocument();
    });
  });

  it("hides shared-only integrations for isolating worker scopes", async () => {
    useConfigStore.setState({
      agents: [
        {
          id: "code",
          display_name: "Scoped Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["lobby"],
          worker_scope: "user",
        },
      ],
      agentPoliciesByAgent: {
        code: makeAgentPolicy("code", {
          effective_execution_scope: "user",
          scope_label: "worker_scope=user",
          scope_source: "agent.worker_scope",
          dashboard_credentials_supported: false,
        }),
      },
    });

    render(<Integrations />);

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });
    fireEvent.keyDown(combobox, { key: "Enter", code: "Enter" });

    await waitFor(() => {
      expect(screen.getByText("Scoped Agent")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText("Scoped Agent"));

    await waitFor(() => {
      expect(
        screen.getByText(
          /dashboard credential setup, editing, and disconnect are only supported/i,
        ),
      ).toBeInTheDocument();
    });

    expect(
      screen.getByText(/home assistant and spotify remain shared-only/i),
    ).toBeInTheDocument();
    expect(
      screen.getByText("worker_scope=shared", { selector: "code" }),
    ).toBeInTheDocument();
    expect(screen.getByText("Google Drive")).toBeInTheDocument();
    expect(screen.queryByText("Spotify")).not.toBeInTheDocument();
    expect(screen.queryByText("Weather")).toBeInTheDocument();
    expect(
      screen.getAllByRole("button", { name: /shared-only config/i }),
    ).toHaveLength(2);
    for (const button of screen.getAllByRole("button", {
      name: /shared-only config/i,
    })) {
      expect(button).toBeDisabled();
    }
  });

  it("treats private agents as isolating scopes in integrations", async () => {
    useConfigStore.setState({
      agents: [
        {
          id: "mind",
          display_name: "Private Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["personal"],
          private: {
            per: "user",
          },
        },
      ],
      agentPoliciesByAgent: {
        mind: makeAgentPolicy("mind", {
          is_private: true,
          effective_execution_scope: "user",
          scope_label: "private.per=user",
          scope_source: "private.per",
          dashboard_credentials_supported: false,
          private_workspace_enabled: true,
        }),
      },
    });

    render(<Integrations />);

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });

    await waitFor(() => {
      expect(screen.getByText("Private Agent")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText("Private Agent"));

    await waitFor(() => {
      expect(
        screen.getByText(
          "Configuring tools for Private Agent (private.per=user).",
        ),
      ).toBeInTheDocument();
      expect(
        screen.getByText(
          /dashboard credential setup, editing, and disconnect are only supported/i,
        ),
      ).toBeInTheDocument();
    });

    expect(screen.getByText("Google Drive")).toBeInTheDocument();
    expect(screen.queryByText("Spotify")).not.toBeInTheDocument();
    expect(screen.queryByText("Weather")).not.toBeInTheDocument();
    expect(screen.getByText("Private Mail")).toBeInTheDocument();
  });

  it("allows scoped OAuth providers to connect for private agents", async () => {
    useConfigStore.setState({
      agents: [
        {
          id: "mind",
          display_name: "Private Agent",
          role: "test",
          tools: ["google_drive"],
          skills: [],
          instructions: [],
          rooms: ["personal"],
          private: {
            per: "user",
          },
        },
      ],
      agentPoliciesByAgent: {
        mind: makeAgentPolicy("mind", {
          is_private: true,
          effective_execution_scope: "user",
          scope_label: "private.per=user",
          scope_source: "private.per",
          dashboard_credentials_supported: false,
          private_workspace_enabled: true,
        }),
      },
    });

    render(<Integrations />);

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });

    await waitFor(() => {
      expect(screen.getByText("Private Agent")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText("Private Agent"));

    await waitFor(() => {
      expect(screen.getByText("Google Drive")).toBeInTheDocument();
    });

    const driveCard = screen.getByText("Google Drive").closest(".h-full");
    expect(driveCard).toBeInstanceOf(HTMLElement);
    fireEvent.click(
      within(driveCard as HTMLElement).getByRole("button", {
        name: /connect/i,
      }),
    );

    await waitFor(() => {
      expect(mockGoogleDriveOnAction).toHaveBeenCalledTimes(1);
    });
    expect(mockToast).not.toHaveBeenCalledWith(
      expect.objectContaining({
        title: "Shared-only dashboard configuration",
      }),
    );
  });

  it("opens Google Drive tool configuration from the OAuth provider card", async () => {
    mockGoogleDriveLoadStatus.mockResolvedValue({
      status: "connected",
      connected: true,
    });
    const googleDriveTools = [
      ...mockTools,
      {
        name: "google_drive",
        display_name: "Google Drive",
        description: "Search, read, upload, and organize files in Google Drive",
        icon: "SiGoogledrive",
        icon_color: "text-green-600",
        category: "productivity",
        status: "available",
        setup_type: "oauth",
        auth_provider: "google_drive",
        config_fields: [
          {
            name: "max_read_size",
            label: "Max Read Size",
            type: "number",
            required: false,
            default: 10485760,
            description: "Maximum file size to read in bytes.",
          },
        ],
        helper_text: null,
        docs_url: null,
        dependencies: null,
      },
    ];
    mockUseTools.mockImplementation(() => ({
      tools: googleDriveTools,
      loading: false,
      refetch: vi.fn(),
      statusAuthoritative: true,
    }));

    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Google Drive")).toBeInTheDocument();
    });

    const driveCard = screen.getByText("Google Drive").closest(".h-full");
    expect(driveCard).toBeInstanceOf(HTMLElement);
    const editButton = await waitFor(() => {
      const button = within(driveCard as HTMLElement).getByRole("button", {
        name: /edit/i,
      });
      expect(button).not.toBeDisabled();
      return button;
    });
    fireEvent.click(editButton);

    await waitFor(() => {
      expect(screen.getByText("Enhanced Config Dialog")).toBeInTheDocument();
    });
    expect(mockGoogleDriveOnAction).not.toHaveBeenCalled();
  });

  it("opens Gmail OAuth provider configuration using the Gmail tool service", async () => {
    mockGoogleGmailLoadStatus.mockResolvedValue({
      status: "connected",
      connected: true,
    });
    const gmailTools = [
      ...mockTools,
      {
        name: "gmail",
        display_name: "Gmail",
        description: "Read and manage Gmail emails",
        icon: "SiGmail",
        icon_color: "text-red-500",
        category: "email",
        status: "available",
        setup_type: "oauth",
        auth_provider: "google_gmail",
        config_fields: [
          {
            name: "max_results",
            label: "Max Results",
            type: "number",
            required: false,
            default: 10,
            description: "Maximum emails to return.",
          },
        ],
        helper_text: null,
        docs_url: null,
        dependencies: null,
      },
    ];
    mockUseTools.mockImplementation(() => ({
      tools: gmailTools,
      loading: false,
      refetch: vi.fn(),
      statusAuthoritative: true,
    }));

    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Gmail")).toBeInTheDocument();
    });

    const gmailCard = screen.getByText("Gmail").closest(".h-full");
    expect(gmailCard).toBeInstanceOf(HTMLElement);
    const editButton = await waitFor(() => {
      const button = within(gmailCard as HTMLElement).getByRole("button", {
        name: /edit/i,
      });
      expect(button).not.toBeDisabled();
      return button;
    });
    fireEvent.click(editButton);

    await waitFor(() => {
      expect(screen.getByText("Enhanced Config Dialog")).toBeInTheDocument();
      expect(screen.getByText("Service: gmail")).toBeInTheDocument();
    });
    expect(mockGoogleGmailOnAction).not.toHaveBeenCalled();
  });

  it("connects plugin OAuth providers discovered from backend tool metadata", async () => {
    const pluginTools = [
      {
        name: "acme_drive",
        display_name: "Acme Drive",
        description: "Search Acme Drive files",
        icon: "AcmeIcon",
        icon_color: "text-cyan-600",
        category: "productivity",
        status: "requires_config",
        setup_type: "oauth",
        auth_provider: "acme_drive",
        config_fields: null,
        helper_text: null,
        docs_url: null,
        dependencies: null,
      },
    ];
    mockUseTools.mockImplementation(() => ({
      tools: pluginTools,
      loading: false,
      refetch: vi.fn(),
      statusAuthoritative: true,
    }));

    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Acme Drive")).toBeInTheDocument();
    });

    const acmeCard = screen.getByText("Acme Drive").closest(".h-full");
    expect(acmeCard).toBeInstanceOf(HTMLElement);
    fireEvent.click(
      within(acmeCard as HTMLElement).getByRole("button", {
        name: /connect/i,
      }),
    );

    await waitFor(() => {
      expect(mockGenericOAuthOnAction).toHaveBeenCalledWith("acme_drive");
    });
    expect(
      screen.queryByText(/Connect acme_drive first/i),
    ).not.toBeInTheDocument();
  });

  it("ignores stale shared-scope reloads after switching scope mid-action", async () => {
    const spotifyAction = createDeferred();
    mockSpotifyOnAction.mockImplementation(() => spotifyAction.promise);
    useConfigStore.setState({
      agents: [
        {
          id: "mind",
          display_name: "Private Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["personal"],
          private: {
            per: "user",
          },
        },
      ],
      agentPoliciesByAgent: {
        mind: makeAgentPolicy("mind", {
          is_private: true,
          effective_execution_scope: "user",
          scope_label: "private.per=user",
          scope_source: "private.per",
          dashboard_credentials_supported: false,
          private_workspace_enabled: true,
        }),
      },
    });

    render(<Integrations />);

    await waitFor(() => {
      expect(screen.getByText("Spotify")).toBeInTheDocument();
      expect(screen.getByText("Weather")).toBeInTheDocument();
    });

    const spotifyCard = screen.getByText("Spotify").closest(".h-full");
    expect(spotifyCard).toBeInstanceOf(HTMLElement);
    fireEvent.click(
      within(spotifyCard as HTMLElement).getByRole("button", {
        name: "Connect",
      }),
    );

    await waitFor(() => {
      expect(mockSpotifyOnAction).toHaveBeenCalledTimes(1);
    });

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });

    await waitFor(() => {
      expect(screen.getByText("Private Agent")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText("Private Agent"));

    await waitFor(() => {
      expect(
        screen.getByText(
          "Configuring tools for Private Agent (private.per=user).",
        ),
      ).toBeInTheDocument();
      expect(screen.getByText("Private Mail")).toBeInTheDocument();
      expect(screen.queryByText("Weather")).not.toBeInTheDocument();
    });

    await act(async () => {
      spotifyAction.resolve();
      await spotifyAction.promise;
    });

    await waitFor(() => {
      expect(screen.getByText("Private Mail")).toBeInTheDocument();
      expect(screen.queryByText("Weather")).not.toBeInTheDocument();
    });
  });

  it("clears the selected scope when policy preview disappears", async () => {
    useConfigStore.setState({
      agents: [
        {
          id: "mind",
          display_name: "Private Agent",
          role: "test",
          tools: ["gmail"],
          skills: [],
          instructions: [],
          rooms: ["personal"],
          private: {
            per: "user",
          },
        },
      ],
      agentPoliciesByAgent: {
        mind: makeAgentPolicy("mind", {
          is_private: true,
          effective_execution_scope: "user",
          scope_label: "private.per=user",
          scope_source: "private.per",
          dashboard_credentials_supported: false,
          private_workspace_enabled: true,
        }),
      },
    });

    render(<Integrations />);

    const combobox = screen.getByRole("combobox");
    fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });

    await waitFor(() => {
      expect(screen.getByText("Private Agent")).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText("Private Agent"));

    await waitFor(() => {
      expect(
        screen.getByText(
          "Configuring tools for Private Agent (private.per=user).",
        ),
      ).toBeInTheDocument();
    });
    await waitFor(() => {
      expect(screen.getByText("Private Mail")).toBeInTheDocument();
    });

    await act(async () => {
      useConfigStore.setState({
        agentPoliciesByAgent: {},
      });
    });

    expect(screen.queryByText("Private Mail")).not.toBeInTheDocument();

    await waitFor(() => {
      expect(
        screen.queryByText(
          "Configuring tools for Private Agent (private.per=user).",
        ),
      ).not.toBeInTheDocument();
    });

    await waitFor(() => {
      expect(mockUseTools).toHaveBeenLastCalledWith(null, null);
    });
    await waitFor(() => {
      expect(screen.getByText("Weather")).toBeInTheDocument();
    });
  });
});
