import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";

import { ProviderProps } from "@/types";
import { FILTER_FIELD } from "@/types/filters";

import { AccountsSelector } from "./accounts-selector";

const multiSelectContentSpy = vi.fn();
const multiSelectSpy = vi.fn();

vi.mock("next/navigation", () => ({
  useSearchParams: () => new URLSearchParams(),
}));

vi.mock("@/hooks/use-url-filters", () => ({
  useUrlFilters: () => ({
    navigateWithParams: vi.fn(),
  }),
}));

vi.mock("@/components/icons/providers-badge", () => ({
  AWSProviderBadge: () => <span>AWS</span>,
  AzureProviderBadge: () => <span>Azure</span>,
  GCPProviderBadge: () => <span>GCP</span>,
  CloudflareProviderBadge: () => <span>Cloudflare</span>,
  GitHubProviderBadge: () => <span>GitHub</span>,
  GoogleWorkspaceProviderBadge: () => <span>Google Workspace</span>,
  IacProviderBadge: () => <span>IaC</span>,
  ImageProviderBadge: () => <span>Image</span>,
  KS8ProviderBadge: () => <span>Kubernetes</span>,
  M365ProviderBadge: () => <span>M365</span>,
  MongoDBAtlasProviderBadge: () => <span>MongoDB Atlas</span>,
  OpenStackProviderBadge: () => <span>OpenStack</span>,
  OracleCloudProviderBadge: () => <span>Oracle Cloud</span>,
  AlibabaCloudProviderBadge: () => <span>Alibaba Cloud</span>,
  VercelProviderBadge: () => <span>Vercel</span>,
  OktaProviderBadge: () => <span>Okta</span>,
}));

vi.mock("@/components/shadcn/select/multiselect", () => ({
  MultiSelect: ({
    children,
    open,
    onOpenChange,
  }: {
    children: React.ReactNode;
    open?: boolean;
    onOpenChange?: (open: boolean) => void;
  }) => {
    multiSelectSpy({ open });
    return (
      <div data-open={String(open)}>
        <button type="button" onClick={() => onOpenChange?.(true)}>
          Open selector
        </button>
        {children}
      </div>
    );
  },
  MultiSelectTrigger: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="trigger">{children}</div>
  ),
  MultiSelectValue: ({ placeholder }: { placeholder: string }) => (
    <span>{placeholder}</span>
  ),
  MultiSelectContent: ({
    children,
    search,
  }: {
    children: React.ReactNode;
    search?: unknown;
  }) => {
    multiSelectContentSpy(search);
    return <div>{children}</div>;
  },
  MultiSelectItem: ({
    children,
    disabled,
    value,
    keywords,
    onSelect,
  }: {
    children: React.ReactNode;
    disabled?: boolean;
    value: string;
    keywords?: string[];
    onSelect?: (value: string) => void;
  }) => (
    <button
      type="button"
      data-value={value}
      data-keywords={keywords?.join("|")}
      data-disabled={disabled ? "true" : "false"}
      onClick={() => onSelect?.(value)}
    >
      {children}
    </button>
  ),
}));

const providers: ProviderProps[] = [
  {
    id: "provider-1",
    type: "providers" as const,
    attributes: {
      provider: "aws" as const,
      is_dynamic: false,
      uid: "123456789012",
      alias: "Production AWS",
      status: "completed" as const,
      resources: 0,
      connection: {
        connected: true,
        last_checked_at: "2026-04-13T00:00:00Z",
      },
      scanner_args: {
        only_logs: false,
        excluded_checks: [],
        aws_retries_max_attempts: 3,
      },
      inserted_at: "2026-04-13T00:00:00Z",
      updated_at: "2026-04-13T00:00:00Z",
      created_by: {
        object: "user",
        id: "user-1",
      },
    },
    relationships: {
      secret: {
        data: null,
      },
      provider_groups: {
        meta: {
          count: 0,
        },
        data: [],
      },
    },
  },
];

describe("AccountsSelector", () => {
  it("passes searchable dropdown defaults to MultiSelectContent", () => {
    render(<AccountsSelector providers={providers} />);

    expect(multiSelectContentSpy).toHaveBeenCalledWith({
      placeholder: "Search Providers...",
      emptyMessage: "No Providers found.",
    });
    expect(screen.getByText("All Providers")).toBeInTheDocument();
    expect(screen.getByText("Production AWS")).toBeInTheDocument();
  });

  it("supports contextual placeholder and empty-selection copy", () => {
    render(
      <AccountsSelector
        providers={providers}
        placeholder="Select a Provider"
        emptySelectionLabel="No provider selected"
        clearSelectionLabel="Clear provider selection"
      />,
    );

    expect(screen.getByText("Select a Provider")).toBeInTheDocument();
    expect(screen.getByText("No provider selected")).toBeInTheDocument();
  });

  it("allows disabling search explicitly", () => {
    render(<AccountsSelector providers={providers} search={false} />);

    expect(multiSelectContentSpy).toHaveBeenLastCalledWith(false);
  });

  it("passes visible account labels as search keywords instead of only the internal id", () => {
    render(<AccountsSelector providers={providers} />);

    expect(
      screen.getByText("Production AWS").closest("[data-value]"),
    ).toHaveAttribute(
      "data-keywords",
      expect.stringContaining("Production AWS"),
    );
    expect(
      screen.getByText("Production AWS").closest("[data-value]"),
    ).toHaveAttribute("data-keywords", expect.stringContaining("123456789012"));
  });

  it("can use provider UID values for pages whose API filters by provider_uid__in", () => {
    render(
      <AccountsSelector
        providers={providers}
        filterKey={FILTER_FIELD.PROVIDER_UID}
      />,
    );

    expect(
      screen.getByText("Production AWS").closest("[data-value]"),
    ).toHaveAttribute("data-value", "123456789012");
  });

  it("disables select all when every account is already shown", () => {
    render(<AccountsSelector providers={providers} />);

    expect(
      screen.getByRole("option", { name: /select all Providers/i }),
    ).toHaveAttribute("aria-disabled", "true");
    expect(screen.getByText("All selected")).toBeInTheDocument();
  });

  it("marks configured account values as disabled", () => {
    render(
      <AccountsSelector
        providers={providers}
        disabledValues={["provider-1"]}
      />,
    );

    expect(
      screen.getByText("Production AWS").closest("[data-value]"),
    ).toHaveAttribute("data-disabled", "true");
    expect(screen.getByText("Disconnected")).toBeInTheDocument();
  });

  it("can close the dropdown after selecting a launch-scan provider", async () => {
    const user = userEvent.setup();

    render(
      <AccountsSelector
        providers={providers}
        closeOnSelect
        onBatchChange={vi.fn()}
        selectedValues={[]}
      />,
    );

    await user.click(screen.getByRole("button", { name: /open selector/i }));
    expect(multiSelectSpy).toHaveBeenLastCalledWith({ open: true });

    await user.click(screen.getByRole("button", { name: /production aws/i }));

    expect(multiSelectSpy).toHaveBeenLastCalledWith({ open: false });
  });

  it("shows the provider icon next to the name in the trigger for a single selection", async () => {
    render(
      <AccountsSelector
        providers={providers}
        onBatchChange={vi.fn()}
        selectedValues={["provider-1"]}
      />,
    );

    const trigger = screen.getByTestId("trigger");
    expect(await within(trigger).findByText("AWS")).toBeInTheDocument();
    expect(within(trigger).getByText("Production AWS")).toBeInTheDocument();
  });

  it("renders one icon per selected account without deduping by provider type", async () => {
    const secondAws = {
      ...providers[0],
      id: "provider-2",
      attributes: {
        ...providers[0].attributes,
        uid: "999999999999",
        alias: "Staging AWS",
      },
    };

    render(
      <AccountsSelector
        providers={[providers[0], secondAws]}
        onBatchChange={vi.fn()}
        selectedValues={["provider-1", "provider-2"]}
      />,
    );

    const trigger = screen.getByTestId("trigger");
    // Two AWS accounts -> two AWS icons in the trigger (no dedupe).
    expect(await within(trigger).findAllByText("AWS")).toHaveLength(2);
    expect(
      within(trigger).getByText("2 Providers selected"),
    ).toBeInTheDocument();
  });
});
