import { describe, expect, it, beforeEach, afterAll } from "vitest";
import { eq, sql } from "drizzle-orm";
import { createDatabase, closeDatabase } from "../src/client.js";
import { schema, seedReleaseGates, evaluateReleaseGates, summarizeReleaseGates } from "../src/index.js";
import { BUILT_IN_RELEASE_GATES } from "@app/shared-types";

const { db, pool } = createDatabase();

async function reset() {
  await db.delete(schema.productAnalyticsEvents);
  await db.delete(schema.releaseGates);
  await db
    .delete(schema.users)
    .where(sql`${schema.users.email} LIKE 'release-gates-test-%@example.invalid'`);
}

async function createTestUser(id: string) {
  const [user] = await db
    .insert(schema.users)
    .values({
      id,
      email: `release-gates-test-${id.slice(0, 8)}@example.invalid`,
      displayName: "Release Gate Test",
      locale: "sv-SE",
    })
    .returning({ id: schema.users.id });
  return user!.id;
}

beforeEach(async () => {
  await reset();
});

afterAll(async () => {
  await reset();
  await closeDatabase();
});

describe("release gates", () => {
  it("seeds built-in gates idempotently", async () => {
    await seedReleaseGates(db);
    const first = await db.select().from(schema.releaseGates);
    expect(first.length).toBe(BUILT_IN_RELEASE_GATES.length);

    await seedReleaseGates(db);
    const second = await db.select().from(schema.releaseGates);
    expect(second.length).toBe(BUILT_IN_RELEASE_GATES.length);
  });

  it("evaluates first_scan_rate from product_analytics_events", async () => {
    await seedReleaseGates(db);
    const userA = await createTestUser("11111111-1111-1111-1111-111111111111");
    const userB = await createTestUser("22222222-2222-2222-2222-222222222222");
    const now = new Date();
    await db.insert(schema.productAnalyticsEvents).values([
      { eventName: "account_created", userId: userA, occurredAt: now, receivedAt: now, properties: {} },
      { eventName: "account_created", userId: userB, occurredAt: now, receivedAt: now, properties: {} },
      { eventName: "scan_completed", userId: userA, occurredAt: now, receivedAt: now, properties: {} },
    ]);

    const results = await evaluateReleaseGates(db);
    const firstScan = results.find((g) => g.gateKey === "first_scan_rate");
    expect(firstScan).toBeDefined();
    expect(firstScan?.value).toBeCloseTo(0.5);
    expect(firstScan?.status).toBe("failed"); // target 70%
  });

  it("summarizes overall go/no-go verdict", async () => {
    await seedReleaseGates(db);
    const results = await evaluateReleaseGates(db);
    const summary = summarizeReleaseGates(results);
    expect(summary.overall).toBeOneOf(["go", "no_go", "pending"]);
    expect(summary.passed + summary.failed + summary.pending + summary.notMeasurable).toBe(
      BUILT_IN_RELEASE_GATES.length,
    );
  });

  it("persists evaluation results", async () => {
    await seedReleaseGates(db);
    const user = await createTestUser("33333333-3333-3333-3333-333333333333");
    const now = new Date();
    await db.insert(schema.productAnalyticsEvents).values([
      { eventName: "account_created", userId: user, occurredAt: now, receivedAt: now, properties: {} },
      { eventName: "scan_completed", userId: user, occurredAt: now, receivedAt: now, properties: {} },
    ]);

    await evaluateReleaseGates(db);
    const [gate] = await db.select().from(schema.releaseGates).where(eq(schema.releaseGates.gateKey, "first_scan_rate"));
    expect(gate?.lastValue).toBeCloseTo(1);
    expect(gate?.status).toBe("passed");
    expect(gate?.lastEvaluatedAt).not.toBeNull();
  });
});
