// frontend/tests/connectors/AddAccountMenu.test.tsx — phase-16 계정 추가(OAuth) 메뉴
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { AddAccountMenu } from "@/components/connectors/AddAccountMenu";
import { connectorsApi } from "@/lib/connectors/api";

vi.mock("@/lib/connectors/api", () => ({
  connectorsApi: { providers: vi.fn(), oauthStart: vi.fn() },
}));

const providersMock = vi.mocked(connectorsApi.providers);
const oauthStartMock = vi.mocked(connectorsApi.oauthStart);
const assignMock = vi.fn();
const originalLocation = window.location;

beforeEach(() => {
  providersMock.mockReset();
  oauthStartMock.mockReset();
  assignMock.mockReset();
  // jsdom location.assign 은 non-configurable → location 객체 자체를 교체
  Object.defineProperty(window, "location", {
    configurable: true,
    writable: true,
    value: { ...originalLocation, assign: assignMock },
  });
});
afterEach(() => {
  Object.defineProperty(window, "location", {
    configurable: true,
    writable: true,
    value: originalLocation,
  });
  vi.restoreAllMocks();
});

const PROVIDERS = [
  { domain: "mail", provider: "gmail", label: "Gmail", configured: true },
  { domain: "mail", provider: "outlook", label: "Outlook", configured: false },
];

describe("AddAccountMenu", () => {
  it("provider 가 없으면 아무것도 렌더하지 않는다", async () => {
    providersMock.mockResolvedValue([]);
    const { container } = render(<AddAccountMenu domain="mail" redirectAfter="/settings" />);
    await waitFor(() => expect(providersMock).toHaveBeenCalledWith("mail"));
    expect(container.textContent).toBe("");
  });

  it("열면 configured/미구성 provider 를 보여준다", async () => {
    providersMock.mockResolvedValue(PROVIDERS);
    render(<AddAccountMenu domain="mail" redirectAfter="/settings?tab=mail" />);
    const btn = await screen.findByText("계정 추가");
    fireEvent.click(btn);
    expect(screen.getByRole("menuitem", { name: /Gmail/ })).not.toBeDisabled();
    expect(screen.getByRole("menuitem", { name: /Outlook/ })).toBeDisabled(); // 미구성
    expect(screen.getByText("설정 필요")).toBeInTheDocument();
  });

  it("configured provider 클릭 시 oauthStart 후 authorize_url 로 이동", async () => {
    providersMock.mockResolvedValue(PROVIDERS);
    oauthStartMock.mockResolvedValue({ authorize_url: "https://accounts.google.com/o/oauth2/x" });
    render(<AddAccountMenu domain="mail" redirectAfter="/settings?tab=mail" />);
    fireEvent.click(await screen.findByText("계정 추가"));
    fireEvent.click(screen.getByRole("menuitem", { name: /Gmail/ }));
    await waitFor(() =>
      expect(oauthStartMock).toHaveBeenCalledWith("mail", "gmail", "/settings?tab=mail"),
    );
    await waitFor(() =>
      expect(assignMock).toHaveBeenCalledWith("https://accounts.google.com/o/oauth2/x"),
    );
  });

  it("oauthStart 실패 시 onError 토스트 호출", async () => {
    providersMock.mockResolvedValue(PROVIDERS);
    oauthStartMock.mockRejectedValue(new Error("400"));
    const onError = vi.fn();
    render(<AddAccountMenu domain="mail" redirectAfter="/settings" onError={onError} />);
    fireEvent.click(await screen.findByText("계정 추가"));
    fireEvent.click(screen.getByRole("menuitem", { name: /Gmail/ }));
    await waitFor(() => expect(onError).toHaveBeenCalledWith("Gmail 연결을 시작하지 못했어요"));
  });
});
