/* Copyright 2026 Marimo. All rights reserved. */

import type { SortingState } from "@tanstack/react-table";
import { describe, expect, it, vi } from "vitest";

describe("multi-column sorting logic", () => {
  // Extract the core sorting logic to test in isolation
  const handleSort = (options: {
    columnId: string;
    desc: boolean;
    sortingState: SortingState;
    setSorting: (state: SortingState) => void;
    clearSorting: () => void;
  }) => {
    const { columnId, desc, sortingState, setSorting, clearSorting } = options;
    const currentSort = sortingState.find((s) => s.id === columnId);

    if (currentSort && currentSort.desc === desc) {
      // Clicking the same sort again - remove it
      clearSorting();
    } else {
      // New sort or different direction - move to end of stack
      const otherSorts = sortingState.filter((s) => s.id !== columnId);
      const newSort = { id: columnId, desc };
      setSorting([...otherSorts, newSort]);
    }
  };

  it("implements stack-based sorting: moves re-clicked column to end", () => {
    const sortingState: SortingState = [
      { id: "name", desc: false },
      { id: "age", desc: false },
    ];
    const setSorting = vi.fn();
    const clearSorting = vi.fn();

    // Click Desc on age - should move age to end with desc=true
    handleSort({
      columnId: "age",
      desc: true,
      sortingState,
      setSorting,
      clearSorting,
    });

    expect(setSorting).toHaveBeenCalledWith([
      { id: "name", desc: false },
      { id: "age", desc: true },
    ]);
    expect(clearSorting).not.toHaveBeenCalled();
  });

  it("removes sort when clicking same direction twice", () => {
    const sortingState: SortingState = [{ id: "age", desc: false }];
    const setSorting = vi.fn();
    const clearSorting = vi.fn();

    // Click Asc on age again - should remove the sort
    handleSort({
      columnId: "age",
      desc: false,
      sortingState,
      setSorting,
      clearSorting,
    });

    expect(clearSorting).toHaveBeenCalled();
    expect(setSorting).not.toHaveBeenCalled();
  });

  it("adds new column to end of stack", () => {
    const sortingState: SortingState = [{ id: "name", desc: false }];
    const setSorting = vi.fn();
    const clearSorting = vi.fn();

    // Click Asc on age - should add age to end
    handleSort({
      columnId: "age",
      desc: false,
      sortingState,
      setSorting,
      clearSorting,
    });

    expect(setSorting).toHaveBeenCalledWith([
      { id: "name", desc: false },
      { id: "age", desc: false },
    ]);
    expect(clearSorting).not.toHaveBeenCalled();
  });

  it("toggles sort direction when clicking opposite", () => {
    const sortingState: SortingState = [{ id: "age", desc: false }];
    const setSorting = vi.fn();
    const clearSorting = vi.fn();

    // Click Desc on age - should toggle to descending
    handleSort({
      columnId: "age",
      desc: true,
      sortingState,
      setSorting,
      clearSorting,
    });

    expect(setSorting).toHaveBeenCalledWith([{ id: "age", desc: true }]);
    expect(clearSorting).not.toHaveBeenCalled();
  });

  it("correctly calculates priority numbers", () => {
    const sortingState: SortingState = [
      { id: "name", desc: false },
      { id: "age", desc: true },
      { id: "dept", desc: false },
    ];

    // Priority is index + 1
    const nameSort = sortingState.find((s) => s.id === "name");
    const namePriority = nameSort ? sortingState.indexOf(nameSort) + 1 : null;
    expect(namePriority).toBe(1);

    const deptSort = sortingState.find((s) => s.id === "dept");
    const deptPriority = deptSort ? sortingState.indexOf(deptSort) + 1 : null;
    expect(deptPriority).toBe(3);
  });

  it("handles removing column from middle of stack", () => {
    const sortingState: SortingState = [
      { id: "name", desc: false },
      { id: "age", desc: true },
      { id: "dept", desc: false },
    ];
    const setSorting = vi.fn();
    const clearSorting = vi.fn();

    // Click Desc on age again - should remove it
    handleSort({
      columnId: "age",
      desc: true,
      sortingState,
      setSorting,
      clearSorting,
    });

    expect(clearSorting).toHaveBeenCalled();
    // After removal, dept should move from priority 3 to priority 2
  });
});
