/**
 * InitiateConnectionDialog Component Tests
 * Following TDD - write tests first!
 */

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

describe("InitiateConnectionDialog", (): void => {
  const mockOnInitiate = vi.fn();
  const mockOnCancel = vi.fn();

  it("should render when open is true", (): void => {
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    expect(screen.getByText(/connect to remote instance/i)).toBeInTheDocument();
  });

  it("should not render when open is false", (): void => {
    const { container } = render(
      <InitiateConnectionDialog open={false} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    expect(container.firstChild).toBeNull();
  });

  it("should render PDA-friendly title", (): void => {
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    expect(screen.getByText(/connect to remote instance/i)).toBeInTheDocument();
  });

  it("should render PDA-friendly description", (): void => {
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    expect(screen.getByText(/enter the url/i)).toBeInTheDocument();
  });

  it("should render URL input field", (): void => {
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    expect(screen.getByLabelText(/instance url/i)).toBeInTheDocument();
  });

  it("should render Connect button", (): void => {
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    expect(screen.getByRole("button", { name: /connect/i })).toBeInTheDocument();
  });

  it("should render Cancel button", (): void => {
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    expect(screen.getByRole("button", { name: /cancel/i })).toBeInTheDocument();
  });

  it("should call onCancel when cancel button clicked", async (): Promise<void> => {
    const user = userEvent.setup();
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );

    const cancelButton = screen.getByRole("button", { name: /cancel/i });
    await user.click(cancelButton);

    expect(mockOnCancel).toHaveBeenCalledTimes(1);
  });

  it("should call onInitiate with URL when connect button clicked", async (): Promise<void> => {
    const user = userEvent.setup();
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );

    const urlInput = screen.getByLabelText(/instance url/i);
    await user.type(urlInput, "https://mosaic.example.com");

    const connectButton = screen.getByRole("button", { name: /connect/i });
    await user.click(connectButton);

    expect(mockOnInitiate).toHaveBeenCalledWith("https://mosaic.example.com");
  });

  it("should disable connect button when URL is empty", (): void => {
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );
    const connectButton = screen.getByRole("button", { name: /connect/i });
    expect(connectButton).toBeDisabled();
  });

  it("should enable connect button when URL is entered", async (): Promise<void> => {
    const user = userEvent.setup();
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );

    const urlInput = screen.getByLabelText(/instance url/i);
    await user.type(urlInput, "https://mosaic.example.com");

    const connectButton = screen.getByRole("button", { name: /connect/i });
    expect(connectButton).not.toBeDisabled();
  });

  it("should show validation error for invalid URL", async (): Promise<void> => {
    const user = userEvent.setup();
    render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );

    const urlInput = screen.getByLabelText(/instance url/i);
    await user.type(urlInput, "not-a-valid-url");

    const connectButton = screen.getByRole("button", { name: /connect/i });
    await user.click(connectButton);

    expect(screen.getByText(/please enter a valid url/i)).toBeInTheDocument();
  });

  it("should clear input when dialog is closed", async (): Promise<void> => {
    const user = userEvent.setup();
    const { rerender } = render(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );

    const urlInput = screen.getByLabelText(/instance url/i);
    await user.type(urlInput, "https://mosaic.example.com");

    // Close dialog
    rerender(
      <InitiateConnectionDialog open={false} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );

    // Reopen dialog
    rerender(
      <InitiateConnectionDialog open={true} onInitiate={mockOnInitiate} onCancel={mockOnCancel} />
    );

    const newUrlInput = screen.getByLabelText(/instance url/i);
    expect(newUrlInput).toHaveValue("");
  });

  it("should show loading state when isLoading is true", (): void => {
    render(
      <InitiateConnectionDialog
        open={true}
        onInitiate={mockOnInitiate}
        onCancel={mockOnCancel}
        isLoading={true}
      />
    );
    expect(screen.getByText(/connecting/i)).toBeInTheDocument();
  });

  it("should disable buttons when isLoading is true", (): void => {
    render(
      <InitiateConnectionDialog
        open={true}
        onInitiate={mockOnInitiate}
        onCancel={mockOnCancel}
        isLoading={true}
      />
    );
    const connectButton = screen.getByRole("button", { name: /connecting/i });
    const cancelButton = screen.getByRole("button", { name: /cancel/i });

    expect(connectButton).toBeDisabled();
    expect(cancelButton).toBeDisabled();
  });

  it("should display error message when error prop is provided", (): void => {
    render(
      <InitiateConnectionDialog
        open={true}
        onInitiate={mockOnInitiate}
        onCancel={mockOnCancel}
        error="Unable to connect to remote instance"
      />
    );
    expect(screen.getByText("Unable to connect to remote instance")).toBeInTheDocument();
  });
});
