/**
 * Integration Tests - Testing interactions between multiple routes/features
 * These tests verify critical app behavior that spans multiple components.
 */
import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from "vitest";
import Fastify, { FastifyInstance } from "fastify";
import cookie from "@fastify/cookie";
import jwt from "@fastify/jwt";
import sensible from "@fastify/sensible";
import fastifyMultipart from "@fastify/multipart";
import { createClient, Client } from "@libsql/client";
import { drizzle } from "drizzle-orm/libsql";

// Use vi.hoisted to create the db BEFORE mocks are set up
const { testClient, testDb } = vi.hoisted(() => {
  const { createClient } = require("@libsql/client");
  const { drizzle } = require("drizzle-orm/libsql");
  const client = createClient({ url: ":memory:" });
  const db = drizzle(client);
  return { testClient: client, testDb: db };
});

// Mock modules
vi.mock("../db/client.js", () => ({
  db: testDb,
  migrationsReady: Promise.resolve(),
}));

vi.mock("../plugins/env.js", () => ({
  env: {
    AUTH_ENABLED: false,
    NODE_ENV: "test",
    LOG_LEVEL: "silent",
    PORT: 3000,
    CORS_ORIGINS: "*",
    JWT_SECRET: "test-secret",
    REFRESH_SECRET: "test-refresh-secret",
    COOKIE_SECRET: "test-cookie-secret",
    ACCESS_TOKEN_TTL_MINUTES: 15,
    REFRESH_TOKEN_TTL_DAYS: 7,
  },
}));

vi.mock("../plugins/auth.js", () => ({
  requireAuth: async () => {},
  getAnonymousUserId: () => 999999999,
}));

// Import routes
const { doseRoutes } = await import("../routes/doses.js");
const { shareRoutes } = await import("../routes/share.js");
const { medicationRoutes } = await import("../routes/medications.js");
const { settingsRoutes } = await import("../routes/settings.js");

// =============================================================================
// Schema & Setup
// =============================================================================

async function createSchema(client: Client) {
  const tables = [
    `CREATE TABLE IF NOT EXISTS users (
      id integer PRIMARY KEY AUTOINCREMENT,
      username text NOT NULL UNIQUE,
      password_hash text,
      avatar_url text,
      auth_provider text NOT NULL DEFAULT 'local',
      oidc_subject text,
      is_active integer NOT NULL DEFAULT 1,
      last_login_at integer,
      created_at integer NOT NULL DEFAULT (strftime('%s','now')),
      updated_at integer NOT NULL DEFAULT (strftime('%s','now'))
    )`,
    `CREATE TABLE IF NOT EXISTS medications (
      id integer PRIMARY KEY AUTOINCREMENT,
      user_id integer NOT NULL,
      name text NOT NULL,
      generic_name text,
      taken_by_json text NOT NULL DEFAULT '[]',
      pack_count integer NOT NULL DEFAULT 1,
      blisters_per_pack integer NOT NULL DEFAULT 1,
      pills_per_blister integer NOT NULL DEFAULT 1,
      loose_tablets integer NOT NULL DEFAULT 0,
      pill_weight_mg integer,
      usage_json text NOT NULL DEFAULT '[]',
      every_json text NOT NULL DEFAULT '[]',
      start_json text NOT NULL DEFAULT '[]',
      image_url text,
      expiry_date text,
      notes text,
      intake_reminders_enabled integer NOT NULL DEFAULT 0,
      updated_at integer NOT NULL DEFAULT (strftime('%s','now')),
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )`,
    `CREATE TABLE IF NOT EXISTS user_settings (
      id integer PRIMARY KEY AUTOINCREMENT,
      user_id integer NOT NULL UNIQUE,
      email_enabled integer NOT NULL DEFAULT 0,
      notification_email text,
      email_stock_reminders integer NOT NULL DEFAULT 1,
      email_intake_reminders integer NOT NULL DEFAULT 1,
      shoutrrr_enabled integer NOT NULL DEFAULT 0,
      shoutrrr_url text,
      shoutrrr_stock_reminders integer NOT NULL DEFAULT 1,
      shoutrrr_intake_reminders integer NOT NULL DEFAULT 1,
      reminder_days_before integer NOT NULL DEFAULT 7,
      repeat_daily_reminders integer NOT NULL DEFAULT 0,
      skip_reminders_for_taken_doses integer NOT NULL DEFAULT 0,
      repeat_reminders_enabled integer NOT NULL DEFAULT 0,
      reminder_repeat_interval_minutes integer NOT NULL DEFAULT 30,
      max_nagging_reminders integer NOT NULL DEFAULT 5,
      low_stock_days integer NOT NULL DEFAULT 30,
      normal_stock_days integer NOT NULL DEFAULT 90,
      high_stock_days integer NOT NULL DEFAULT 180,
      expiry_warning_days integer NOT NULL DEFAULT 90,
      language text NOT NULL DEFAULT 'en',
      stock_calculation_mode text NOT NULL DEFAULT 'automatic',
      last_auto_email_sent text,
      last_notification_type text,
      last_notification_channel text,
      updated_at integer NOT NULL DEFAULT (strftime('%s','now')),
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )`,
    `CREATE TABLE IF NOT EXISTS share_tokens (
      id integer PRIMARY KEY AUTOINCREMENT,
      user_id integer NOT NULL,
      token text NOT NULL UNIQUE,
      taken_by text NOT NULL,
      schedule_days integer NOT NULL DEFAULT 30,
      created_at integer NOT NULL DEFAULT (strftime('%s','now')),
      expires_at integer,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )`,
    `CREATE TABLE IF NOT EXISTS dose_tracking (
      id integer PRIMARY KEY AUTOINCREMENT,
      user_id integer NOT NULL,
      dose_id text NOT NULL,
      taken_at integer NOT NULL DEFAULT (strftime('%s','now')),
      marked_by text,
      dismissed integer NOT NULL DEFAULT 0,
      FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )`,
  ];

  for (const sql of tables) {
    await client.execute(sql);
  }
}

async function clearData(client: Client) {
  await client.execute("DELETE FROM dose_tracking");
  await client.execute("DELETE FROM share_tokens");
  await client.execute("DELETE FROM user_settings");
  await client.execute("DELETE FROM medications");
  await client.execute("DELETE FROM users");
  await client.execute("DELETE FROM sqlite_sequence");
}

// =============================================================================
// Tests
// =============================================================================

describe("Integration Tests", () => {
  let app: FastifyInstance;
  const userId = 999999999;

  beforeAll(async () => {
    await createSchema(testClient);

    app = Fastify({ logger: false });
    await app.register(sensible);
    await app.register(cookie, { secret: "test-cookie-secret" });
    await app.register(jwt, {
      secret: "test-jwt-secret",
      cookie: { cookieName: "access_token", signed: false },
    });
    await app.register(fastifyMultipart, { limits: { fileSize: 10 * 1024 * 1024 } });

    app.decorate("config", {
      accessSecret: "test-jwt-secret",
      refreshSecret: "test-refresh-secret",
      accessTtl: 15,
      refreshTtl: 7,
      cookieOptions: { httpOnly: true, sameSite: "lax", secure: false, path: "/" },
      refreshCookieOptions: { httpOnly: true, sameSite: "lax", secure: false, path: "/" },
    });

    await app.register(doseRoutes);
    await app.register(shareRoutes);
    await app.register(medicationRoutes);
    await app.register(settingsRoutes);

    await app.ready();
  });

  afterAll(async () => {
    await app.close();
    testClient.close();
  });

  beforeEach(async () => {
    await clearData(testClient);
    await testClient.execute(
      "INSERT INTO users (id, username, auth_provider) VALUES (999999999, '__anonymous__', 'anonymous')"
    );
  });

  // ---------------------------------------------------------------------------
  // Medication Update + Dose Tracking Cleanup
  // ---------------------------------------------------------------------------

  describe("Medication Update cleans up old dose tracking", () => {
    it("should delete doses before new start date when start date is moved forward", async () => {
      // Create medication starting Jan 1
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Test Med",
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });
      const medId = createRes.json().id;

      // Mark some doses (Jan 1, Jan 2, Jan 5, Jan 10)
      const jan1 = new Date("2025-01-01T08:00:00.000Z").getTime();
      const jan2 = new Date("2025-01-02T08:00:00.000Z").getTime();
      const jan5 = new Date("2025-01-05T08:00:00.000Z").getTime();
      const jan10 = new Date("2025-01-10T08:00:00.000Z").getTime();

      for (const ts of [jan1, jan2, jan5, jan10]) {
        await app.inject({
          method: "POST",
          url: "/doses/taken",
          payload: { doseId: `${medId}-0-${ts}` },
        });
      }

      // Verify 4 doses exist
      const beforeUpdate = await testClient.execute({
        sql: `SELECT COUNT(*) as count FROM dose_tracking WHERE dose_id LIKE ?`,
        args: [`${medId}-%`],
      });
      expect(beforeUpdate.rows[0].count).toBe(4);

      // Update medication to start Jan 5 (should delete Jan 1 and Jan 2 doses)
      await app.inject({
        method: "PUT",
        url: `/medications/${medId}`,
        payload: {
          name: "Test Med",
          blisters: [{ usage: 1, every: 1, start: "2025-01-05T08:00:00.000Z" }],
        },
      });

      // Verify only 2 doses remain (Jan 5 and Jan 10)
      const afterUpdate = await testClient.execute({
        sql: `SELECT dose_id FROM dose_tracking WHERE dose_id LIKE ? ORDER BY dose_id`,
        args: [`${medId}-%`],
      });
      expect(afterUpdate.rows.length).toBe(2);
      expect(afterUpdate.rows[0].dose_id).toContain(String(jan5));
      expect(afterUpdate.rows[1].dose_id).toContain(String(jan10));
    });

    it("should keep all doses when start date is moved backward", async () => {
      // Create medication starting Jan 10
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Test Med",
          blisters: [{ usage: 1, every: 1, start: "2025-01-10T08:00:00.000Z" }],
        },
      });
      const medId = createRes.json().id;

      // Mark dose on Jan 10
      const jan10 = new Date("2025-01-10T08:00:00.000Z").getTime();
      await app.inject({
        method: "POST",
        url: "/doses/taken",
        payload: { doseId: `${medId}-0-${jan10}` },
      });

      // Update to start Jan 1 (earlier)
      await app.inject({
        method: "PUT",
        url: `/medications/${medId}`,
        payload: {
          name: "Test Med",
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      // Dose should still exist
      const afterUpdate = await testClient.execute({
        sql: `SELECT COUNT(*) as count FROM dose_tracking WHERE dose_id LIKE ?`,
        args: [`${medId}-%`],
      });
      expect(afterUpdate.rows[0].count).toBe(1);
    });

    it("should handle multiple blisters with different start dates", async () => {
      // Create medication with 2 schedules: Jan 1 morning and Jan 5 evening
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Test Med",
          blisters: [
            { usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" },
            { usage: 0.5, every: 1, start: "2025-01-05T20:00:00.000Z" },
          ],
        },
      });
      const medId = createRes.json().id;

      // Mark doses for both schedules
      const jan1_8am = new Date("2025-01-01T08:00:00.000Z").getTime();
      const jan3_8am = new Date("2025-01-03T08:00:00.000Z").getTime();
      const jan5_8pm = new Date("2025-01-05T20:00:00.000Z").getTime();
      const jan6_8pm = new Date("2025-01-06T20:00:00.000Z").getTime();

      await app.inject({ method: "POST", url: "/doses/taken", payload: { doseId: `${medId}-0-${jan1_8am}` } });
      await app.inject({ method: "POST", url: "/doses/taken", payload: { doseId: `${medId}-0-${jan3_8am}` } });
      await app.inject({ method: "POST", url: "/doses/taken", payload: { doseId: `${medId}-1-${jan5_8pm}` } });
      await app.inject({ method: "POST", url: "/doses/taken", payload: { doseId: `${medId}-1-${jan6_8pm}` } });

      // 4 doses total
      const before = await testClient.execute({
        sql: `SELECT COUNT(*) as count FROM dose_tracking WHERE dose_id LIKE ?`,
        args: [`${medId}-%`],
      });
      expect(before.rows[0].count).toBe(4);

      // Update: move first schedule to Jan 4
      // Earliest start is now Jan 4, so Jan 1 and Jan 3 doses should be deleted
      await app.inject({
        method: "PUT",
        url: `/medications/${medId}`,
        payload: {
          name: "Test Med",
          blisters: [
            { usage: 1, every: 1, start: "2025-01-04T08:00:00.000Z" },
            { usage: 0.5, every: 1, start: "2025-01-05T20:00:00.000Z" },
          ],
        },
      });

      // Should have 2 doses left (Jan 5 and Jan 6 evening doses)
      const after = await testClient.execute({
        sql: `SELECT dose_id FROM dose_tracking WHERE dose_id LIKE ?`,
        args: [`${medId}-%`],
      });
      expect(after.rows.length).toBe(2);
    });
  });

  // ---------------------------------------------------------------------------
  // Share Link + Dose Tracking Integration
  // ---------------------------------------------------------------------------

  describe("Share links and dose tracking integration", () => {
    it("should allow marking/unmarking doses via share link with correct markedBy", async () => {
      // Create medication for Daniel
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Aspirin",
          takenBy: ["Daniel"],
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });
      const medId = createRes.json().id;

      // Create share token for Daniel
      const shareRes = await app.inject({
        method: "POST",
        url: "/share",
        payload: { takenBy: "Daniel", scheduleDays: 30 },
      });
      const token = shareRes.json().token;

      // Mark dose via share link
      const doseId = `${medId}-0-${new Date("2025-01-01T08:00:00.000Z").getTime()}`;
      await app.inject({
        method: "POST",
        url: `/share/${token}/doses`,
        payload: { doseId },
      });

      // Verify markedBy is "Daniel"
      const result = await testClient.execute({
        sql: `SELECT marked_by FROM dose_tracking WHERE dose_id = ?`,
        args: [doseId],
      });
      expect(result.rows[0].marked_by).toBe("Daniel");

      // Unmark via share link
      await app.inject({
        method: "DELETE",
        url: `/share/${token}/doses/${encodeURIComponent(doseId)}`,
      });

      // Verify deleted
      const afterDelete = await testClient.execute({
        sql: `SELECT COUNT(*) as count FROM dose_tracking WHERE dose_id = ?`,
        args: [doseId],
      });
      expect(afterDelete.rows[0].count).toBe(0);
    });

    it("should show medication in shared schedule after marking dose", async () => {
      // Create medication
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Vitamin D",
          takenBy: ["Anna"],
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });
      const medId = createRes.json().id;

      // Create share token
      const shareRes = await app.inject({
        method: "POST",
        url: "/share",
        payload: { takenBy: "Anna", scheduleDays: 30 },
      });
      const token = shareRes.json().token;

      // Mark a dose
      const doseId = `${medId}-0-${new Date("2025-01-05T08:00:00.000Z").getTime()}`;
      await app.inject({
        method: "POST",
        url: `/share/${token}/doses`,
        payload: { doseId },
      });

      // Get shared schedule
      const scheduleRes = await app.inject({
        method: "GET",
        url: `/share/${token}`,
      });

      const data = scheduleRes.json();
      expect(data.takenBy).toBe("Anna");
      expect(data.medications).toHaveLength(1);
      expect(data.medications[0].name).toBe("Vitamin D");
    });
  });

  // ---------------------------------------------------------------------------
  // Settings + Stock Calculation Mode
  // ---------------------------------------------------------------------------

  describe("Settings affect stock calculation", () => {
    it("should persist stock calculation mode across requests", async () => {
      // Set to manual mode
      await app.inject({
        method: "PUT",
        url: "/settings",
        payload: {
          emailEnabled: false,
          notificationEmail: "",
          reminderDaysBefore: 7,
          repeatDailyReminders: false,
          lowStockDays: 30,
          normalStockDays: 90,
          highStockDays: 180,
          shoutrrrEnabled: false,
          shoutrrrUrl: "",
          emailStockReminders: true,
          emailIntakeReminders: true,
          shoutrrrStockReminders: true,
          shoutrrrIntakeReminders: true,
          language: "en",
          stockCalculationMode: "manual",
        },
      });

      // Verify it's saved
      const getRes = await app.inject({
        method: "GET",
        url: "/settings",
      });
      expect(getRes.json().stockCalculationMode).toBe("manual");

      // Change to automatic
      await app.inject({
        method: "PUT",
        url: "/settings",
        payload: {
          emailEnabled: false,
          notificationEmail: "",
          reminderDaysBefore: 7,
          repeatDailyReminders: false,
          lowStockDays: 30,
          normalStockDays: 90,
          highStockDays: 180,
          shoutrrrEnabled: false,
          shoutrrrUrl: "",
          emailStockReminders: true,
          emailIntakeReminders: true,
          shoutrrrStockReminders: true,
          shoutrrrIntakeReminders: true,
          language: "en",
          stockCalculationMode: "automatic",
        },
      });

      const getRes2 = await app.inject({
        method: "GET",
        url: "/settings",
      });
      expect(getRes2.json().stockCalculationMode).toBe("automatic");
    });
  });

  // ---------------------------------------------------------------------------
  // Multi-Person Medication Scenarios
  // ---------------------------------------------------------------------------

  describe("Multi-person medication scenarios", () => {
    it("should create separate share links for different people", async () => {
      // Create medication for multiple people
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Family Vitamins",
          takenBy: ["Daniel", "Anna", "Max"],
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      // Create share links for each person
      const danielShare = await app.inject({
        method: "POST",
        url: "/share",
        payload: { takenBy: "Daniel", scheduleDays: 30 },
      });

      const annaShare = await app.inject({
        method: "POST",
        url: "/share",
        payload: { takenBy: "Anna", scheduleDays: 30 },
      });

      // Both should succeed with different tokens
      expect(danielShare.statusCode).toBe(200);
      expect(annaShare.statusCode).toBe(200);
      expect(danielShare.json().token).not.toBe(annaShare.json().token);

      // Each share link should show correct person
      const danielSchedule = await app.inject({
        method: "GET",
        url: `/share/${danielShare.json().token}`,
      });
      expect(danielSchedule.json().takenBy).toBe("Daniel");

      const annaSchedule = await app.inject({
        method: "GET",
        url: `/share/${annaShare.json().token}`,
      });
      expect(annaSchedule.json().takenBy).toBe("Anna");
    });

    it("should list all people correctly via /share/people", async () => {
      // Create multiple medications
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Med 1",
          takenBy: ["Daniel", "Anna"],
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Med 2",
          takenBy: ["Max"],
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Med 3",
          takenBy: ["Daniel"], // Daniel again
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      // Get all people
      const peopleRes = await app.inject({
        method: "GET",
        url: "/share/people",
      });

      const people = peopleRes.json().people;
      expect(people).toContain("Daniel");
      expect(people).toContain("Anna");
      expect(people).toContain("Max");
      expect(people.length).toBe(3); // No duplicates
    });
  });

  // ---------------------------------------------------------------------------
  // Edge Cases
  // ---------------------------------------------------------------------------

  describe("Edge cases", () => {
    it("should handle medication with 0 stock correctly", async () => {
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Empty Med",
          packCount: 0,
          blistersPerPack: 1,
          pillsPerBlister: 10,
          looseTablets: 0,
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      expect(createRes.statusCode).toBe(200);
      expect(createRes.json().packCount).toBe(0);
    });

    it("should handle medication with very high pill count", async () => {
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Bulk Med",
          packCount: 100,
          blistersPerPack: 10,
          pillsPerBlister: 100,
          looseTablets: 500,
          blisters: [{ usage: 0.5, every: 7, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      expect(createRes.statusCode).toBe(200);
      // Total: 100 * 10 * 100 + 500 = 100500 pills
    });

    it("should handle fractional pill usage", async () => {
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Half-Pill Med",
          blisters: [
            { usage: 0.5, every: 1, start: "2025-01-01T08:00:00.000Z" },
            { usage: 0.25, every: 1, start: "2025-01-01T20:00:00.000Z" },
          ],
        },
      });

      expect(createRes.statusCode).toBe(200);
      expect(createRes.json().blisters[0].usage).toBe(0.5);
      expect(createRes.json().blisters[1].usage).toBe(0.25);
    });

    it("should handle weekly medication schedule", async () => {
      const createRes = await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Weekly Med",
          blisters: [{ usage: 1, every: 7, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      expect(createRes.statusCode).toBe(200);
      expect(createRes.json().blisters[0].every).toBe(7);
    });
  });

  // ---------------------------------------------------------------------------
  // Planner Usage Calculation - POST /medications/usage
  // This is a CRITICAL feature for the app - calculates if stock is enough
  // ---------------------------------------------------------------------------

  describe("Planner usage calculation", () => {
    it("should calculate correct usage for daily medication", async () => {
      // Create medication: 2 packs × 3 blisters × 10 pills = 60 pills total
      // Schedule: 1 pill daily starting Jan 1
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Daily Med",
          packCount: 2,
          blistersPerPack: 3,
          pillsPerBlister: 10,
          looseTablets: 0,
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      // Calculate usage for Jan 1-10 (10 days = 10 pills needed)
      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2025-01-01T00:00:00.000Z",
          endDate: "2025-01-11T00:00:00.000Z", // 10 days
        },
      });

      expect(response.statusCode).toBe(200);
      const data = response.json();
      expect(data).toHaveLength(1);
      expect(data[0].medicationName).toBe("Daily Med");
      expect(data[0].plannerUsage).toBe(10); // 10 days × 1 pill
      // Note: 'enough' depends on current stock after consumption since start date
      // Since test runs ~364 days after Jan 1, most pills are consumed
    });

    it("should detect insufficient stock", async () => {
      // Create medication: 1 pack × 1 blister × 5 pills = 5 pills total
      // Schedule: 1 pill daily
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Low Stock Med",
          packCount: 1,
          blistersPerPack: 1,
          pillsPerBlister: 5,
          looseTablets: 0,
          blisters: [{ usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      // Calculate usage for 10 days (needs 10 pills, only have 5 originally)
      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2025-01-01T00:00:00.000Z",
          endDate: "2025-01-11T00:00:00.000Z",
        },
      });

      expect(response.statusCode).toBe(200);
      const data = response.json();
      expect(data[0].plannerUsage).toBe(10);
      expect(data[0].enough).toBe(false); // Not enough!
    });

    it("should calculate weekly medication usage correctly", async () => {
      // Create medication: 10 pills total
      // Schedule: 1 pill every 7 days starting Jan 1
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Weekly Med",
          packCount: 1,
          blistersPerPack: 1,
          pillsPerBlister: 10,
          blisters: [{ usage: 1, every: 7, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      // Calculate usage for 30 days (should need ~4-5 pills)
      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2025-01-01T00:00:00.000Z",
          endDate: "2025-01-31T00:00:00.000Z", // 30 days
        },
      });

      expect(response.statusCode).toBe(200);
      const data = response.json();
      // Jan 1, 8, 15, 22, 29 = 5 doses
      expect(data[0].plannerUsage).toBe(5);
    });

    it("should handle multiple intake schedules per medication", async () => {
      // Create medication with morning and evening doses
      // 30 pills total, 1.5 pills per day (1 morning + 0.5 evening)
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Twice Daily Med",
          packCount: 1,
          blistersPerPack: 1,
          pillsPerBlister: 30,
          blisters: [
            { usage: 1, every: 1, start: "2025-01-01T08:00:00.000Z" },   // Morning: 1 pill
            { usage: 0.5, every: 1, start: "2025-01-01T20:00:00.000Z" }, // Evening: 0.5 pill
          ],
        },
      });

      // Calculate for 10 days
      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2025-01-01T00:00:00.000Z",
          endDate: "2025-01-11T00:00:00.000Z",
        },
      });

      expect(response.statusCode).toBe(200);
      const data = response.json();
      // 10 days × (1 + 0.5) = 15 pills
      expect(data[0].plannerUsage).toBe(15);
    });

    it("should calculate correct blisters needed", async () => {
      // 10 pills per blister, need 25 pills → need 3 blisters
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Blister Med",
          packCount: 5,
          blistersPerPack: 1,
          pillsPerBlister: 10,
          blisters: [{ usage: 2.5, every: 1, start: "2025-01-01T08:00:00.000Z" }],
        },
      });

      // 10 days × 2.5 pills = 25 pills needed
      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2025-01-01T00:00:00.000Z",
          endDate: "2025-01-11T00:00:00.000Z",
        },
      });

      expect(response.statusCode).toBe(200);
      const data = response.json();
      expect(data[0].plannerUsage).toBe(25);
      expect(data[0].blistersNeeded).toBe(3); // ceil(25/10)
      expect(data[0].blisterSize).toBe(10);
    });

    it("should reject invalid date range", async () => {
      // End before start
      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2025-01-15T00:00:00.000Z",
          endDate: "2025-01-01T00:00:00.000Z",
        },
      });

      expect(response.statusCode).toBe(400);
    });

    it("should handle medication not yet started", async () => {
      // Medication starts in the future
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Future Med",
          packCount: 1,
          blistersPerPack: 1,
          pillsPerBlister: 30,
          blisters: [{ usage: 1, every: 1, start: "2025-06-01T08:00:00.000Z" }], // Starts June
        },
      });

      // Query for January (before start)
      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2025-01-01T00:00:00.000Z",
          endDate: "2025-01-31T00:00:00.000Z",
        },
      });

      expect(response.statusCode).toBe(200);
      const data = response.json();
      expect(data[0].plannerUsage).toBe(0); // No usage before start
    });

    it("should return correct totalPills based on current stock", async () => {
      // Fresh medication with future start date = no consumption yet
      await app.inject({
        method: "POST",
        url: "/medications",
        payload: {
          name: "Fresh Med",
          packCount: 2,
          blistersPerPack: 2,
          pillsPerBlister: 10,
          looseTablets: 5,
          // Start in far future so no consumption
          blisters: [{ usage: 1, every: 1, start: "2030-01-01T08:00:00.000Z" }],
        },
      });

      const response = await app.inject({
        method: "POST",
        url: "/medications/usage",
        payload: {
          startDate: "2030-01-01T00:00:00.000Z",
          endDate: "2030-01-11T00:00:00.000Z",
        },
      });

      expect(response.statusCode).toBe(200);
      const data = response.json();
      // Total: 2 packs × 2 blisters × 10 pills + 5 loose = 45 pills
      expect(data[0].totalPills).toBe(45);
      expect(data[0].plannerUsage).toBe(10);
      expect(data[0].enough).toBe(true); // 45 > 10
    });
  });
});
