import { afterEach, describe, expect, it } from "vitest";
import { openDatabase, type CompanionDatabase } from "../src/database.js";
import { TripStore } from "../src/trips.js";

let database: CompanionDatabase | null = null;

function setup() {
  database = openDatabase(":memory:");
  database.prepare(
    `INSERT INTO mobile_devices (id, name, token_hash, created_at, last_seen_at)
     VALUES ('phone', 'Test phone', 'token', '2026-08-01T10:00:00.000Z', '2026-08-01T10:00:00.000Z')`
  ).run();
  return new TripStore(database);
}

function location(capturedAt: string, longitude: number, speedKph: number) {
  return {
    deviceId: "phone",
    capturedAt,
    latitude: 55.6761,
    longitude,
    accuracyMeters: 4,
    speedKph,
    phoneBatteryPercent: 80
  };
}

afterEach(() => {
  database?.close();
  database = null;
});

describe("trip recording", () => {
  it("starts on movement, records a route, and ends after stationary timeout", () => {
    const trips = setup();
    expect(trips.record(location("2026-08-01T10:00:00.000Z", 12.5683, 0))).toEqual({ tripId: null, active: false });

    const started = trips.record(location("2026-08-01T10:00:10.000Z", 12.5684, 20));
    expect(started.active).toBe(true);
    trips.record(location("2026-08-01T10:01:10.000Z", 12.5784, 45));
    trips.record(location("2026-08-01T10:04:11.000Z", 12.5784, 0));

    const list = trips.list().trips;
    expect(list).toHaveLength(1);
    expect(list[0]).toMatchObject({ active: false, pointCount: 2, peakSpeedKph: 45 });
    expect(list[0]!.distanceKm).toBeGreaterThan(0.5);

    const detail = trips.detail(started.tripId!);
    expect(detail?.points).toHaveLength(2);
    expect(detail?.pins).toEqual(expect.arrayContaining([
      expect.objectContaining({ type: "start" }),
      expect.objectContaining({ type: "peak-speed", speedKph: 45 }),
      expect.objectContaining({ type: "end" })
    ]));
  });

  it("uses nearby vehicle telemetry for speed and battery statistics", () => {
    const trips = setup();
    const first = Date.parse("2026-08-01T12:00:00.000Z");
    database!.prepare(
      `INSERT INTO car_telemetry_samples
       (recorded_at, speed_kph, battery_percent, total_consumption_kwh)
       VALUES (?, 60, 78, 12.4), (?, 40, 74, 14.1)`
    ).run(first, first + 60_000);

    const started = trips.record(location("2026-08-01T12:00:00.000Z", 12.5683, 0));
    trips.record(location("2026-08-01T12:01:00.000Z", 12.5783, 0));
    const detail = trips.detail(started.tripId!);

    expect(detail).toMatchObject({
      peakSpeedKph: 60,
      vehicleBatteryStartPercent: 78,
      vehicleBatteryEndPercent: 74,
      batteryConsumedPercent: 4,
      energyConsumedKwh: expect.closeTo(1.7, 5)
    });
  });

  it("does not create trips from inaccurate or stationary locations", () => {
    const trips = setup();
    trips.record({ ...location("2026-08-01T13:00:00.000Z", 12.5, 80), accuracyMeters: 250 });
    trips.record(location("2026-08-01T13:01:00.000Z", 12.5, 2));
    expect(trips.list().trips).toEqual([]);
  });
});
