import { describe, it, expect, vi } from "vitest";
import { orderByEintreffzeit } from "../eintreffzeit";
import type { Coordinates } from "../types";

const origin: Coordinates = { lat: 48.2079, lng: 15.6229 };

type Hit = { id: string; brigadeCoords: Coordinates | null };

const nah: Hit = { id: "nah", brigadeCoords: { lat: 48.21, lng: 15.63 } };
const fern: Hit = { id: "fern", brigadeCoords: { lat: 48.2082, lng: 16.3738 } };
const ohne: Hit = { id: "ohne", brigadeCoords: null };

describe("orderByEintreffzeit", () => {
  it("(a) OSRM-Erfolg: sortiert aufsteigend nach Dauer, mode=osrm", async () => {
    // OSRM gibt fern eine kürzere Dauer als nah -> Reihenfolge folgt OSRM, nicht Luftlinie.
    const etaTable = vi.fn().mockResolvedValue({
      durations: [[0, 300, 100]], // origin -> [nah, fern]
      distances: [[0, 4000, 2000]],
    });
    const result = await orderByEintreffzeit(origin, [nah, fern], etaTable);
    expect(result.map((r) => r.id)).toEqual(["fern", "nah"]);
    expect(result.every((r) => r.eta.mode === "osrm")).toBe(true);
    expect(result.every((r) => r.eta.isFallback === false)).toBe(true);
    expect(result[0]!.eta.durationSec).toBe(100);
  });

  it("(b) OSRM-Wurf: kompletter Haversine-Fallback, isFallback=true, sortiert", async () => {
    const etaTable = vi.fn().mockRejectedValue(new Error("osrm down"));
    const result = await orderByEintreffzeit(origin, [fern, nah], etaTable);
    expect(result.every((r) => r.eta.mode === "haversine")).toBe(true);
    expect(result.every((r) => r.eta.isFallback === true)).toBe(true);
    // nah ist näher (Luftlinie) als fern -> nah zuerst
    expect(result.map((r) => r.id)).toEqual(["nah", "fern"]);
    expect(result[0]!.eta.durationSec).not.toBeNull();
  });

  it("(c) Kandidaten ohne Koordinaten landen am Ende mit durationSec=null", async () => {
    const etaTable = vi.fn().mockResolvedValue({
      durations: [[0, 300, 100]],
      distances: [[0, 4000, 2000]],
    });
    const result = await orderByEintreffzeit(origin, [ohne, nah, fern], etaTable);
    expect(result[result.length - 1]!.id).toBe("ohne");
    expect(result[result.length - 1]!.eta.durationSec).toBeNull();
  });

  it("(d) leere Liste -> leeres Ergebnis, OSRM wird nicht gerufen", async () => {
    const etaTable = vi.fn();
    const result = await orderByEintreffzeit(origin, [], etaTable);
    expect(result).toEqual([]);
    expect(etaTable).not.toHaveBeenCalled();
  });

  it("(e) stabile Sortierung bei gleicher Dauer (Eingabereihenfolge bleibt)", async () => {
    const a: Hit = { id: "a", brigadeCoords: { lat: 48.21, lng: 15.63 } };
    const b: Hit = { id: "b", brigadeCoords: { lat: 48.22, lng: 15.64 } };
    const etaTable = vi.fn().mockResolvedValue({
      durations: [[0, 200, 200]],
      distances: [[0, 1000, 1000]],
    });
    const result = await orderByEintreffzeit(origin, [a, b], etaTable);
    expect(result.map((r) => r.id)).toEqual(["a", "b"]);
  });
});
