import { describe, expect, it } from "vitest";
import { bhS1RowsDefaultOrder } from "@/lib/clean-logs/__tests__/bh-s1-fixture";
import { sortCleanLogs } from "@/lib/clean-logs/sort";
import { CLEAN_TASK_STATUS } from "@/lib/config";
import type { CleanLogItem } from "@/lib/types";

const [R4, R1, R2, R5, R3, R8, R6, R7] = bhS1RowsDefaultOrder();
const DEFAULT_ORDER = [R4, R1, R2, R5, R3, R8, R6, R7];

function keys(items: readonly CleanLogItem[]): string[] {
  return items.map((r) => r.row_key);
}

function rankRow(overrides: Partial<CleanLogItem>): CleanLogItem {
  const row = bhS1RowsDefaultOrder()[0];
  return {
    ...row,
    id: null,
    report_id: null,
    unscheduled: false,
    facility_name: "テスト",
    model_name: "CC1",
    serial_number: overrides.row_key ?? "S-X",
    scheduled_at: "2026-11-01T02:00:00+09:00",
    status_1h: null,
    status_1h_minutes: null,
    status_30m: null,
    status_30m_minutes: null,
    departed: true,
    result_pending: false,
    completion_rate: 50,
    grade: "○",
    consecutive_problem_days: 0,
    escalation_level: null,
    ...overrides,
  };
}

describe("sortCleanLogs — 表S1（指示書BH §3）", () => {
  it("S1-1: sort null — 既定順のまま", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, null, "asc"))).toEqual(keys(DEFAULT_ORDER));
  });

  it("S1-1b: sort null — 入力順を変えない", () => {
    const input = [R8, R1, R7, R2, R6, R3, R5, R4];
    expect(keys(sortCleanLogs(input, null, "asc"))).toEqual(keys(input));
  });

  it("S1-2: scheduled_at asc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "scheduled_at", "asc"))).toEqual([
      "tt-105",
      "tt-106",
      "tt-107",
      "tt-103",
      "rp-9001",
      "tt-101",
      "tt-102",
      "tt-104",
    ]);
  });

  it("S1-4: completion_rate asc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "completion_rate", "asc"))).toEqual([
      "rp-9001",
      "tt-102",
      "tt-107",
      "tt-105",
      "tt-106",
      "tt-101",
      "tt-103",
      "tt-104",
    ]);
  });

  it("S1-5: completion_rate desc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "completion_rate", "desc"))).toEqual([
      "tt-101",
      "tt-106",
      "tt-105",
      "tt-107",
      "tt-102",
      "rp-9001",
      "tt-103",
      "tt-104",
    ]);
  });

  it("S1-6: grade asc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "grade", "asc"))).toEqual([
      "rp-9001",
      "tt-103",
      "tt-102",
      "tt-107",
      "tt-105",
      "tt-101",
      "tt-106",
      "tt-104",
    ]);
  });

  it("S1-7: grade desc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "grade", "desc"))).toEqual([
      "tt-101",
      "tt-106",
      "tt-107",
      "tt-105",
      "tt-102",
      "rp-9001",
      "tt-103",
      "tt-104",
    ]);
  });

  it("S1-8: departed asc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "departed", "asc"))).toEqual([
      "tt-103",
      "tt-101",
      "tt-102",
      "rp-9001",
      "tt-107",
      "tt-105",
      "tt-106",
      "tt-104",
    ]);
  });

  it("S1-9: departed desc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "departed", "desc"))).toEqual([
      "tt-101",
      "tt-102",
      "rp-9001",
      "tt-107",
      "tt-105",
      "tt-106",
      "tt-103",
      "tt-104",
    ]);
  });

  it("S1-10: task_status asc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "task_status", "asc"))).toEqual([
      "tt-103",
      "tt-107",
      "tt-102",
      "rp-9001",
      "tt-106",
      "tt-105",
      "tt-101",
      "tt-104",
    ]);
  });

  it("S1-11: task_status desc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "task_status", "desc"))).toEqual([
      "tt-101",
      "tt-105",
      "rp-9001",
      "tt-106",
      "tt-102",
      "tt-107",
      "tt-103",
      "tt-104",
    ]);
  });

  it("S1-12: model_name asc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "model_name", "asc"))).toEqual([
      "tt-101",
      "tt-102",
      "rp-9001",
      "tt-107",
      "tt-105",
      "tt-106",
      "tt-103",
      "tt-104",
    ]);
  });

  it("S1-13: model_name desc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "model_name", "desc"))).toEqual([
      "tt-103",
      "tt-101",
      "tt-102",
      "rp-9001",
      "tt-107",
      "tt-105",
      "tt-106",
      "tt-104",
    ]);
  });

  it("S1-14: serial_number asc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "serial_number", "asc"))).toEqual([
      "tt-102",
      "tt-103",
      "tt-101",
      "rp-9001",
      "tt-105",
      "tt-106",
      "tt-107",
      "tt-104",
    ]);
  });

  it("S1-15: serial_number desc", () => {
    expect(keys(sortCleanLogs(DEFAULT_ORDER, "serial_number", "desc"))).toEqual([
      "tt-107",
      "tt-106",
      "tt-105",
      "rp-9001",
      "tt-101",
      "tt-103",
      "tt-102",
      "tt-104",
    ]);
  });

  it("S1-16: grade asc の slice(3, 6)", () => {
    const sorted = sortCleanLogs(DEFAULT_ORDER, "grade", "asc");
    expect(sorted.length).toBe(8);
    expect(keys(sorted.slice(3, 6))).toEqual(["tt-107", "tt-105", "tt-101"]);
  });

  it("S1-17: 入力配列を書き換えない", () => {
    const input = [...DEFAULT_ORDER];
    const before = keys(input);
    sortCleanLogs(input, "grade", "asc");
    expect(keys(input)).toEqual(before);
  });
});

describe("sortCleanLogs — task_status 順位（指示書BH §11 R3）", () => {
  const TS_NULL = rankRow({
    row_key: "ts-null",
    serial_number: "S-null",
    departed: false,
    task_status: null,
    completion_rate: null,
    grade: "×",
  });
  const TS_5 = rankRow({
    row_key: "ts-5",
    serial_number: "S-5",
    task_status: CLEAN_TASK_STATUS.endedAbnormally,
  });
  const TS_2 = rankRow({
    row_key: "ts-2",
    serial_number: "S-2",
    task_status: CLEAN_TASK_STATUS.interrupted,
  });
  const TS_3 = rankRow({
    row_key: "ts-3",
    serial_number: "S-3",
    scheduled_at: "2026-11-01T02:00:00+09:00",
    task_status: CLEAN_TASK_STATUS.cancelled,
  });
  const TS_6 = rankRow({
    row_key: "ts-6",
    serial_number: "S-6",
    scheduled_at: "2026-11-02T21:00:00+09:00",
    task_status: CLEAN_TASK_STATUS.cancelledByRobot,
  });
  const TS_7 = rankRow({
    row_key: "ts-7",
    serial_number: "S-7",
    scheduled_at: "2026-11-01T02:00:00+09:00",
    task_status: 7,
  });
  const TS_NEG = rankRow({
    row_key: "ts-neg",
    serial_number: "S-neg",
    scheduled_at: "2026-11-01T02:00:00+09:00",
    task_status: -1,
  });
  const TS_0 = rankRow({
    row_key: "ts-0",
    serial_number: "S-0",
    task_status: CLEAN_TASK_STATUS.notStarted,
  });
  const TS_1 = rankRow({
    row_key: "ts-1",
    serial_number: "S-1",
    task_status: CLEAN_TASK_STATUS.cleaning,
  });
  const TS_4 = rankRow({
    row_key: "ts-4",
    serial_number: "S-4",
    task_status: CLEAN_TASK_STATUS.completed,
  });
  const TS_PENDING = rankRow({
    row_key: "ts-pending",
    serial_number: "S-pending",
    departed: false,
    result_pending: true,
    task_status: null,
    completion_rate: null,
    grade: "×",
  });

  const shuffled = [
    TS_PENDING,
    TS_4,
    TS_1,
    TS_0,
    TS_NEG,
    TS_7,
    TS_6,
    TS_3,
    TS_2,
    TS_5,
    TS_NULL,
  ];

  const expectedAsc = [
    "ts-null",
    "ts-5",
    "ts-2",
    "ts-6",
    "ts-3",
    "ts-7",
    "ts-neg",
    "ts-0",
    "ts-1",
    "ts-4",
    "ts-pending",
  ];

  const expectedDesc = [
    "ts-4",
    "ts-1",
    "ts-0",
    "ts-7",
    "ts-neg",
    "ts-6",
    "ts-3",
    "ts-2",
    "ts-5",
    "ts-null",
    "ts-pending",
  ];

  it("asc: 順位 0・1・負の値を含む", () => {
    expect(keys(sortCleanLogs(shuffled, "task_status", "asc"))).toEqual(expectedAsc);
  });

  it("desc: 同順位は既定順のまま（reverse しない）", () => {
    expect(keys(sortCleanLogs(shuffled, "task_status", "desc"))).toEqual(expectedDesc);
  });
});
