import { describe, expect, it } from "vitest"

import { alsCsv } from "./screens/csv"
import { kalenderDatei } from "./screens/kalender"
import { dauer, de, deOderStrich, eur, isoTag, schnittpreis, summe } from "./format"

describe("Zahlen im deutschen Format", () => {
  it("setzt Punkt als Tausender- und Komma als Dezimaltrennzeichen", () => {
    expect(de(48250)).toBe("48.250")
    expect(de(1234.5, 1)).toBe("1.234,5")
    expect(eur(89.1)).toBe("89,10")
  })

  it("macht aus fehlenden Werten eine Null, nicht NaN", () => {
    expect(de(null)).toBe("0")
    expect(de(undefined)).toBe("0")
  })

  it("unterscheidet mit deOderStrich zwischen null und unbekannt", () => {
    expect(deOderStrich(0)).toBe("0")
    expect(deOderStrich(null)).toBe("—")
  })
})

describe("dauer", () => {
  it("zeigt unter einer Stunde nur Minuten", () => {
    expect(dauer(2700)).toBe("45 min")
  })

  it("zeigt darüber Stunden und Minuten zweistellig", () => {
    expect(dauer(8040)).toBe("2 h 14 min")
  })

  it("zeigt einen Strich statt „0 min", () => {
    expect(dauer(0)).toBe("—")
    expect(dauer(null)).toBe("—")
  })
})

describe("schnittpreis", () => {
  it("gewichtet nach Menge, nicht nach Anzahl der Tankungen", () => {
    // 10 l zu 2,00 € und 90 l zu 1,00 €: der Schnitt muss nahe 1,10 liegen,
    // nicht bei 1,50 (dem Mittel der Einzelpreise).
    const schnitt = schnittpreis([
      { liters: 10, fuel_total_eur: 20 },
      { liters: 90, fuel_total_eur: 90 },
    ])
    expect(schnitt).toBeCloseTo(1.1, 2)
  })

  it("liefert 0 statt einer Division durch null", () => {
    expect(schnittpreis([])).toBe(0)
    expect(schnittpreis([{ liters: 0, fuel_total_eur: 10 }])).toBe(0)
  })
})

describe("summe", () => {
  it("überspringt fehlende Werte", () => {
    expect(summe([{ a: 1 }, { a: null }, { a: 3 }], (e) => e.a ?? 0)).toBe(4)
  })
})

describe("isoTag", () => {
  it("gibt das lokale Datum aus, nicht das UTC-Datum", () => {
    // 23:30 Ortszeit ist in UTC schon der Folgetag — der Tag darf nicht kippen.
    const spaet = new Date(2026, 7, 11, 23, 30)
    expect(isoTag(spaet)).toBe("2026-08-11")
  })
})

describe("CSV-Ausgabe", () => {
  it("trennt mit Semikolon und schreibt Dezimalkomma", () => {
    const csv = alsCsv(["Strecke", "Ort"], [[42.5, "München"]])
    expect(csv).toContain("Strecke;Ort")
    expect(csv).toContain("42,5;München")
  })

  it("beginnt mit einem BOM, damit Excel die Umlaute richtig liest", () => {
    expect(alsCsv(["a"], [])[0]).toBe("﻿")
  })

  it("schützt Felder mit Semikolon oder Anführungszeichen", () => {
    const csv = alsCsv(["Text"], [['Er sagte "hallo"; dann ging er']])
    expect(csv).toContain('"Er sagte ""hallo""; dann ging er"')
  })
})

describe("Kalenderdatei", () => {
  it("erzeugt einen ganztägigen Termin mit Erinnerung zwei Tage vorher", () => {
    const ics = kalenderDatei("Ölwechsel", "2027-03-14", "laut Prognose")
    expect(ics).toContain("BEGIN:VCALENDAR")
    expect(ics).toContain("DTSTART;VALUE=DATE:20270314")
    expect(ics).toContain("SUMMARY:Ölwechsel")
    expect(ics).toContain("TRIGGER:-P2D")
    expect(ics.trimEnd().endsWith("END:VCALENDAR")).toBe(true)
  })

  it("schützt Sonderzeichen im Titel", () => {
    expect(kalenderDatei("Service; Öl, Filter", "2027-01-01")).toContain(
      "SUMMARY:Service\\; Öl\\, Filter",
    )
  })
})
