// @ts-nocheck
import type { Context, Next } from "hono";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { MAX_TABLO_LIMIT, verifyTabloLimitForUser } from "../../helpers/helpers.js";

const createSupabaseMock = ({
  profileData = { organization_id: 1 },
  organizationPlans = [{ plan: "free" }],
  profileError = null,
  organizationPlanError = null,
  tabloCount = 0,
  tabloError = null,
} = {}) => {
  const profileSingle = vi.fn(async () => ({ data: profileData, error: profileError }));
  const profileEq = vi.fn((column: string) => {
    if (column === "id") {
      return { single: profileSingle };
    }
    return Promise.resolve({ data: organizationPlans, error: organizationPlanError });
  });
  const profileSelect = vi.fn(() => ({ eq: profileEq }));

  const tabloEq = vi.fn(async () => ({ count: tabloCount, error: tabloError }));
  const tabloSelect = vi.fn(() => ({ eq: tabloEq }));

  const from = vi.fn((table: string) => {
    if (table === "profiles") {
      return { select: profileSelect };
    }
    if (table === "tablos") {
      return { select: tabloSelect };
    }
    throw new Error(`Unexpected table ${table}`);
  });

  return {
    from,
    profileSingle,
    profileEq,
    profileSelect,
    tabloEq,
    tabloSelect,
  };
};

const createContext = (supabase: ReturnType<typeof createSupabaseMock>, user: { id: string }) => {
  const json = vi.fn();
  const get = vi.fn((key: string) => {
    if (key === "supabase") return supabase;
    if (key === "user") return user;
    return undefined;
  });

  return {
    get,
    json,
  } as unknown as Context;
};

describe("verifyTabloLimitForUser", () => {
  const user = { id: "test-user" };
  let next: Next;

  beforeEach(() => {
    vi.clearAllMocks();
    next = vi.fn(async () => Promise.resolve());
  });

  it("returns 500 when profile lookup fails", async () => {
    const supabase = createSupabaseMock({
      profileData: null,
      profileError: { message: "db down" },
    });
    const ctx = createContext(supabase, user);

    await verifyTabloLimitForUser(ctx, next);

    expect(ctx.json).toHaveBeenCalledWith({ error: "Failed to get user profile" }, 500);
    expect(next).not.toHaveBeenCalled();
  });

  it("denies free users that reached the tablo limit", async () => {
    const supabase = createSupabaseMock({
      profileData: { organization_id: 1 },
      organizationPlans: [{ plan: "free" }],
      tabloCount: MAX_TABLO_LIMIT,
    });
    const ctx = createContext(supabase, user);

    await verifyTabloLimitForUser(ctx, next);

    expect(ctx.json).toHaveBeenCalledWith({ error: "You have reached your tablo limit" }, 403);
    expect(next).not.toHaveBeenCalled();
  });

  it("allows free users below the limit to proceed", async () => {
    const belowLimitCount = Math.max(0, MAX_TABLO_LIMIT - 1);
    const supabase = createSupabaseMock({
      profileData: { organization_id: 1 },
      organizationPlans: [{ plan: "free" }],
      tabloCount: belowLimitCount,
    });
    const ctx = createContext(supabase, user);

    await verifyTabloLimitForUser(ctx, next);

    expect(next).toHaveBeenCalledTimes(1);
    expect(ctx.json).not.toHaveBeenCalled();
  });

  it("skips tablo count check for non-free plans", async () => {
    const supabase = createSupabaseMock({
      profileData: { organization_id: 1 },
      organizationPlans: [{ plan: "standard" }],
    });
    const ctx = createContext(supabase, user);

    await verifyTabloLimitForUser(ctx, next);

    expect(next).toHaveBeenCalledTimes(1);
    expect(supabase.tabloSelect).not.toHaveBeenCalled();
  });
});
