import React from "react";
import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { BacklinksList } from "../BacklinksList";
import type { KnowledgeBacklink } from "@mosaic/shared";

// Mock Next.js Link component
vi.mock("next/link", () => ({
  default: ({ children, href }: { children: React.ReactNode; href: string }): React.JSX.Element => {
    return <a href={href}>{children}</a>;
  },
}));

describe("BacklinksList", (): void => {
  const mockBacklinks: KnowledgeBacklink[] = [
    {
      id: "link-1",
      sourceId: "entry-1",
      targetId: "entry-2",
      linkText: "target-entry",
      displayText: "Target Entry",
      positionStart: 0,
      positionEnd: 15,
      resolved: true,
      context: "This is a link to [[target-entry]]",
      createdAt: new Date("2026-01-29T10:00:00Z"),
      source: {
        id: "entry-1",
        title: "Source Entry One",
        slug: "source-entry-one",
        summary: "This entry links to the target",
      },
    },
    {
      id: "link-2",
      sourceId: "entry-3",
      targetId: "entry-2",
      linkText: "target-entry",
      displayText: "Another Link",
      positionStart: 10,
      positionEnd: 25,
      resolved: true,
      context: null,
      createdAt: new Date("2026-01-28T15:30:00Z"),
      source: {
        id: "entry-3",
        title: "Source Entry Two",
        slug: "source-entry-two",
        summary: null,
      },
    },
  ];

  it("renders loading state correctly", (): void => {
    render(<BacklinksList backlinks={[]} isLoading={true} />);

    expect(screen.getByText("Backlinks")).toBeInTheDocument();
    // Should show skeleton loaders
    const skeletons = document.querySelectorAll(".animate-pulse");
    expect(skeletons.length).toBeGreaterThan(0);
  });

  it("renders error state correctly", (): void => {
    render(<BacklinksList backlinks={[]} isLoading={false} error="Failed to load backlinks" />);

    expect(screen.getByText("Backlinks")).toBeInTheDocument();
    expect(screen.getByText("Failed to load backlinks")).toBeInTheDocument();
  });

  it("renders empty state when no backlinks exist", (): void => {
    render(<BacklinksList backlinks={[]} isLoading={false} />);

    expect(screen.getByText("Backlinks")).toBeInTheDocument();
    expect(screen.getByText("No other entries link to this page yet.")).toBeInTheDocument();
  });

  it("renders backlinks list correctly", (): void => {
    render(<BacklinksList backlinks={mockBacklinks} isLoading={false} />);

    // Should show title with count
    expect(screen.getByText("Backlinks")).toBeInTheDocument();
    expect(screen.getByText("(2)")).toBeInTheDocument();

    // Should show both backlink titles
    expect(screen.getByText("Source Entry One")).toBeInTheDocument();
    expect(screen.getByText("Source Entry Two")).toBeInTheDocument();

    // Should show summary for first entry
    expect(screen.getByText("This entry links to the target")).toBeInTheDocument();

    // Should show context for first entry
    expect(screen.getByText(/This is a link to \[\[target-entry\]\]/)).toBeInTheDocument();
  });

  it("generates correct links for backlinks", (): void => {
    render(<BacklinksList backlinks={mockBacklinks} isLoading={false} />);

    const links = screen.getAllByRole("link");

    // Should have links to source entries
    expect(links[0]).toHaveAttribute("href", "/knowledge/source-entry-one");
    expect(links[1]).toHaveAttribute("href", "/knowledge/source-entry-two");
  });

  it("displays date information correctly", (): void => {
    render(<BacklinksList backlinks={mockBacklinks} isLoading={false} />);

    // Should display relative dates (implementation depends on current date)
    // Just verify date elements are present
    const timeElements = document.querySelectorAll('[class*="text-xs"]');
    expect(timeElements.length).toBeGreaterThan(0);
  });

  it("handles backlinks without summaries", (): void => {
    const sourceBacklink = mockBacklinks[1];
    if (!sourceBacklink) {
      throw new Error("Test setup error: mockBacklinks[1] is undefined");
    }

    const backlinksWithoutSummary: KnowledgeBacklink[] = [
      {
        id: sourceBacklink.id,
        sourceId: sourceBacklink.sourceId,
        targetId: sourceBacklink.targetId,
        linkText: sourceBacklink.linkText,
        displayText: sourceBacklink.displayText,
        positionStart: sourceBacklink.positionStart,
        positionEnd: sourceBacklink.positionEnd,
        resolved: sourceBacklink.resolved,
        context: sourceBacklink.context,
        createdAt: sourceBacklink.createdAt,
        source: {
          id: sourceBacklink.source.id,
          title: sourceBacklink.source.title,
          slug: sourceBacklink.source.slug,
          summary: null,
        },
      },
    ];

    render(<BacklinksList backlinks={backlinksWithoutSummary} isLoading={false} />);

    expect(screen.getByText("Source Entry Two")).toBeInTheDocument();
    // Summary should not be rendered
    expect(screen.queryByText("This entry links to the target")).not.toBeInTheDocument();
  });

  it("handles backlinks without context", (): void => {
    const sourceBacklink = mockBacklinks[0];
    if (!sourceBacklink) {
      throw new Error("Test setup error: mockBacklinks[0] is undefined");
    }

    const backlinksWithoutContext: KnowledgeBacklink[] = [
      {
        id: sourceBacklink.id,
        sourceId: sourceBacklink.sourceId,
        targetId: sourceBacklink.targetId,
        linkText: sourceBacklink.linkText,
        displayText: sourceBacklink.displayText,
        positionStart: sourceBacklink.positionStart,
        positionEnd: sourceBacklink.positionEnd,
        resolved: sourceBacklink.resolved,
        context: null,
        createdAt: sourceBacklink.createdAt,
        source: sourceBacklink.source,
      },
    ];

    render(<BacklinksList backlinks={backlinksWithoutContext} isLoading={false} />);

    expect(screen.getByText("Source Entry One")).toBeInTheDocument();
    // Context should not be rendered
    expect(screen.queryByText(/This is a link to \[\[target-entry\]\]/)).not.toBeInTheDocument();
  });
});
