import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { AccountSection } from "../AccountSection";

vi.mock("react-router", () => ({
  Link: ({ children, to }: { children: React.ReactNode; to: string }) => (
    <a href={to}>{children}</a>
  ),
}));

const mockLinkSocial = vi.fn();
vi.mock("~/lib/auth-client", () => ({
  authClient: {
    linkSocial: (...args: unknown[]) => mockLinkSocial(...args),
  },
}));

describe("AccountSection", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockLinkSocial.mockResolvedValue({});
  });

  it("shows Connect Discord button when Discord is not linked", () => {
    render(
      <AccountSection
        email="user@example.com"
        linkedAccounts={[{ id: "1", providerId: "credential" }]}
      />
    );
    expect(screen.getByRole("button", { name: /connect discord/i })).toBeInTheDocument();
  });

  it("does not show Connect Discord button when Discord is already linked", () => {
    render(
      <AccountSection
        email="user@example.com"
        linkedAccounts={[
          { id: "1", providerId: "credential" },
          { id: "2", providerId: "discord" },
        ]}
      />
    );
    expect(screen.queryByRole("button", { name: /connect discord/i })).not.toBeInTheDocument();
  });

  it("calls authClient.linkSocial with discord provider on button click", async () => {
    render(
      <AccountSection
        email="user@example.com"
        linkedAccounts={[{ id: "1", providerId: "credential" }]}
      />
    );
    fireEvent.click(screen.getByRole("button", { name: /connect discord/i }));
    await waitFor(() => {
      expect(mockLinkSocial).toHaveBeenCalledWith({
        provider: "discord",
        callbackURL: "/settings?section=account",
      });
    });
  });

  it("shows Redirecting… and disables the button while linking", async () => {
    // Never resolves so we can inspect the in-flight state
    mockLinkSocial.mockReturnValue(new Promise(() => {}));
    render(
      <AccountSection
        email="user@example.com"
        linkedAccounts={[{ id: "1", providerId: "credential" }]}
      />
    );
    fireEvent.click(screen.getByRole("button", { name: /connect discord/i }));
    await waitFor(() => {
      const btn = screen.getByRole("button", { name: /redirecting/i });
      expect(btn).toBeDisabled();
    });
  });

  it("re-enables the button and shows an error message when linkSocial throws", async () => {
    mockLinkSocial.mockRejectedValue(new Error("OAuth failed"));
    render(
      <AccountSection
        email="user@example.com"
        linkedAccounts={[{ id: "1", providerId: "credential" }]}
      />
    );
    fireEvent.click(screen.getByRole("button", { name: /connect discord/i }));
    await waitFor(() => {
      expect(screen.getByRole("button", { name: /connect discord/i })).not.toBeDisabled();
      expect(screen.getByText(/failed to connect discord/i)).toBeInTheDocument();
    });
  });
});
