import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { db, eq } from "@haushaltsApp/db";
import { account, categories, session, transactions, user } from "@haushaltsApp/db/schema";
import app from "../../index";
import { authHeaders, createTestContext, type TestContext } from "../helpers/test-context";

let ctx: TestContext;
let ctx2: TestContext; // Second household for tenant-isolation test
let createdTransactionId: string;

beforeAll(async () => {
  const ts = Date.now();
  ctx = await createTestContext(`tx-a-${ts}`);
  ctx2 = await createTestContext(`tx-b-${ts}`);
});

afterAll(async () => {
  // Clean up both test contexts
  for (const email of [ctx.email, ctx2.email]) {
    const [u] = await db.select().from(user).where(eq(user.email, email));
    if (u) {
      await db.delete(transactions).where(eq(transactions.userId, u.id));
      await db.delete(categories).where(eq(categories.householdId, ctx.householdId));
      await db.delete(session).where(eq(session.userId, u.id));
      await db.delete(account).where(eq(account.userId, u.id));
      await db.delete(user).where(eq(user.id, u.id));
    }
  }
});

describe("Transaction Routes", () => {
  it("POST /api/transactions — creates transaction", async () => {
    const res = await app.request("/api/transactions", {
      method: "POST",
      headers: authHeaders(ctx.token, ctx.householdId),
      body: JSON.stringify({
        amount: 42.5,
        type: "expense",
        description: "Supermarkt",
        date: new Date().toISOString(),
      }),
    });
    expect(res.status).toBe(201);
    const body = (await res.json()) as { transaction: { id: string; amount: string } };
    expect(body.transaction.id).toBeDefined();
    expect(Number(body.transaction.amount)).toBeCloseTo(42.5);
    createdTransactionId = body.transaction.id;
  });

  it("GET /api/transactions — returns list", async () => {
    const res = await app.request("/api/transactions", {
      headers: authHeaders(ctx.token, ctx.householdId),
    });
    expect(res.status).toBe(200);
    const body = (await res.json()) as { transactions: unknown[] };
    expect(Array.isArray(body.transactions)).toBe(true);
    expect(body.transactions.length).toBeGreaterThan(0);
  });

  it("GET /api/transactions/summary — returns income/expense/balance", async () => {
    const res = await app.request("/api/transactions/summary", {
      headers: authHeaders(ctx.token, ctx.householdId),
    });
    expect(res.status).toBe(200);
    const body = (await res.json()) as { income: number; expense: number; balance: number };
    expect(typeof body.income).toBe("number");
    expect(typeof body.expense).toBe("number");
    expect(typeof body.balance).toBe("number");
    expect(body.expense).toBeCloseTo(42.5);
  });

  it("PATCH /api/transactions/:id — updates description", async () => {
    const res = await app.request(`/api/transactions/${createdTransactionId}`, {
      method: "PATCH",
      headers: authHeaders(ctx.token, ctx.householdId),
      body: JSON.stringify({ description: "Updated description" }),
    });
    expect(res.status).toBe(200);
    const body = (await res.json()) as { transaction: { description: string } };
    expect(body.transaction.description).toBe("Updated description");
  });

  it("DELETE /api/transactions/:id — tenant isolation: household B cannot delete household A transaction", async () => {
    // ctx2 tries to delete a transaction that belongs to ctx's household
    const res = await app.request(`/api/transactions/${createdTransactionId}`, {
      method: "DELETE",
      headers: authHeaders(ctx2.token, ctx2.householdId),
    });
    // Must be 404 — not the transaction's household → no result → 404
    expect(res.status).toBe(404);
  });

  it("DELETE /api/transactions/:id — deletes own transaction", async () => {
    const res = await app.request(`/api/transactions/${createdTransactionId}`, {
      method: "DELETE",
      headers: authHeaders(ctx.token, ctx.householdId),
    });
    expect(res.status).toBe(200);
  });
});
