import { describe, expect, it, beforeAll, afterAll } from "vitest";
import { eq, inArray } from "drizzle-orm";
import { createDatabase, closeDatabase, markMilestone, getActivationState, schema } from "@app/database";

describe("activation", () => {
  const { db } = createDatabase();
  const emails = ["act-test-1@example.invalid", "act-test-2@example.invalid"];
  const inviteCodes = ["ACT123", "ACT223"];

  async function cleanup() {
    await db.delete(schema.householdMembers).where(
      inArray(
        schema.householdMembers.householdId,
        db.select({ id: schema.households.id }).from(schema.households).where(inArray(schema.households.inviteCode, inviteCodes)),
      ),
    );
    await db.delete(schema.households).where(inArray(schema.households.inviteCode, inviteCodes));
    await db.delete(schema.users).where(inArray(schema.users.email, emails));
  }

  beforeAll(cleanup);
  afterAll(async () => {
    await cleanup();
    await closeDatabase();
  });

  it("marks first scan and activates household", async () => {
    const [user] = await db
      .insert(schema.users)
      .values({ email: emails[0]!, displayName: "Act" })
      .returning();
    const [household] = await db
      .insert(schema.households)
      .values({ name: "Act family", inviteCode: inviteCodes[0]! })
      .returning();
    await db.insert(schema.householdMembers).values({
      householdId: household.id,
      userId: user.id,
      role: "owner",
    });

    const r1 = await markMilestone(db, household.id, "firstScanCompletedAt");
    expect(r1.wasNew).toBe(true);
    expect(r1.activatedNow).toBe(false);

    await markMilestone(db, household.id, "fifthItemConfirmedAt");
    await markMilestone(db, household.id, "firstRecipeRecommendationViewedAt");
    const r2 = await markMilestone(db, household.id, "firstRecipeSavedOrStartedAt");
    expect(r2.activatedNow).toBe(true);

    const state = await getActivationState(db, household.id);
    expect(state.activatedAt).not.toBeNull();
    expect(state.valueConfirmedAt).toBeNull();

    await markMilestone(db, household.id, "firstCookingSessionCompletedAt");
    const r3 = await markMilestone(db, household.id, "inventoryUpdatedAfterCookingAt");
    expect(r3.valueConfirmedNow).toBe(true);

    const state2 = await getActivationState(db, household.id);
    expect(state2.valueConfirmedAt).not.toBeNull();
  });

  it("idempotent: does not move timestamps backward", async () => {
    const [user] = await db
      .insert(schema.users)
      .values({ email: emails[1]!, displayName: "Act2" })
      .returning();
    const [household] = await db
      .insert(schema.households)
      .values({ name: "Act2 family", inviteCode: inviteCodes[1]! })
      .returning();
    await db.insert(schema.householdMembers).values({
      householdId: household.id,
      userId: user.id,
      role: "owner",
    });

    await markMilestone(db, household.id, "firstScanCompletedAt");
    const state1 = await getActivationState(db, household.id);
    await new Promise((r) => setTimeout(r, 20));
    await markMilestone(db, household.id, "firstScanCompletedAt");
    const state2 = await getActivationState(db, household.id);
    expect(state2.firstScanCompletedAt?.getTime()).toBe(state1.firstScanCompletedAt?.getTime());
  });
});
