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

import { RepositoriesSettingsTab } from "./RepositoriesSettingsTab";
import * as gitRepositoriesApi from "../../../api/git-repositories";

const mockRepositories = [
  {
    id: "repo-1",
    name: "Main Repo",
    path: "/repos/main",
    project_id: "proj-1",
    owner_id: "user-1",
    is_mirror: false,
    remote_url: null,
    last_push: null,
    created_at: null,
  },
];

vi.mock("react-router-dom", async () => {
  const actual = await vi.importActual<typeof import("react-router-dom")>("react-router-dom");
  return {
    ...actual,
    useParams: () => ({ projectId: "proj-1" }),
  };
});

afterEach(() => {
  cleanup();
  vi.restoreAllMocks();
});

describe("RepositoriesSettingsTab", () => {
  it("opens create dialog and clones an existing repository", async () => {
    const listMock = vi.spyOn(gitRepositoriesApi, "listRepositories").mockResolvedValue(mockRepositories);
    const createMock = vi.spyOn(gitRepositoriesApi, "createRepository").mockResolvedValue(mockRepositories[0]);

    render(<RepositoriesSettingsTab />);

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

    fireEvent.click(screen.getByRole("button", { name: /add repository/i }));
    fireEvent.change(screen.getByPlaceholderText(/repository-name/i), {
      target: { value: "New Repo" },
    });
    fireEvent.change(screen.getByPlaceholderText(/owner/i), {
      target: { value: "alice" },
    });
    fireEvent.change(screen.getByPlaceholderText(/repo-name/i), {
      target: { value: "demo" },
    });
    fireEvent.click(screen.getByRole("button", { name: /clone repository/i }));

    await waitFor(() => {
      expect(createMock).toHaveBeenCalledWith("proj-1", {
        name: "New Repo",
        remote_url: "git@git.commumedia.org:alice/demo.git",
      });
    });
    expect(listMock).toHaveBeenCalledTimes(2);
  });

  it("uses advanced url fallback when requested", async () => {
    const listMock = vi.spyOn(gitRepositoriesApi, "listRepositories").mockResolvedValue(mockRepositories);
    const createMock = vi.spyOn(gitRepositoriesApi, "createRepository").mockResolvedValue(mockRepositories[0]);

    render(<RepositoriesSettingsTab />);

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

    fireEvent.click(screen.getByRole("button", { name: /add repository/i }));
    fireEvent.change(screen.getByPlaceholderText(/repository-name/i), {
      target: { value: "New Repo" },
    });
    fireEvent.click(screen.getByRole("button", { name: /use full url instead/i }));
    fireEvent.change(screen.getByPlaceholderText(/https:\/\/github.com\/user\/repo.git/i), {
      target: { value: "https://github.com/user/repo.git" },
    });
    fireEvent.click(screen.getByRole("button", { name: /clone repository/i }));

    await waitFor(() => {
      expect(createMock).toHaveBeenCalledWith("proj-1", {
        name: "New Repo",
        remote_url: "https://github.com/user/repo.git",
      });
    });
    expect(listMock).toHaveBeenCalledTimes(2);
  });

  it("shows validation when cloning without a remote url", async () => {
    vi.spyOn(gitRepositoriesApi, "listRepositories").mockResolvedValue(mockRepositories);
    render(<RepositoriesSettingsTab />);

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

    fireEvent.click(screen.getByRole("button", { name: /add repository/i }));
    fireEvent.change(screen.getByPlaceholderText(/repository-name/i), {
      target: { value: "New Repo" },
    });
    fireEvent.change(screen.getByPlaceholderText(/owner/i), {
      target: { value: "" },
    });
    fireEvent.click(screen.getByRole("button", { name: /clone repository/i }));

    expect(screen.getByText(/owner and repository name are required/i)).toBeInTheDocument();
  });
});
