/**
 * Tests für getPendingSubmissions (Domain-Approval-Queue).
 *
 * Schwerpunkt: Sort-Order-Garantie + Deadline-Computation.
 *   - Legend > Pro > Free Plan-Priority
 *   - Innerhalb gleicher Priority: älteste createdAt zuerst (FIFO)
 *   - deadlineAt = createdAt + 24h, msUntilDeadline negativ wenn überfällig
 */
import { describe, expect, it, vi, beforeEach } from "vitest";

const prismaMock = vi.hoisted(() => ({
  domainSubmission: {
    findMany: vi.fn(),
  },
}));

vi.mock("../../server/utils/prisma", () => ({
  usePrisma: () => prismaMock,
}));

import {
  getPendingSubmissions,
  ADMIN_APPROVAL_SLA_MS,
} from "../../server/db/domains";

beforeEach(() => {
  vi.clearAllMocks();
});

function makeRow(overrides: Partial<Record<string, unknown>> = {}) {
  return {
    id: "sub-id",
    domain: "example.com",
    type: "web",
    yesVotes: 0,
    noVotes: 0,
    status: "in_review",
    createdAt: new Date("2026-05-09T10:00:00Z"),
    userId: "user-id",
    postId: null,
    customDomain: { id: "cd-id" },
    user: { id: "user-id", nickname: "nick", plan: "free" },
    ...overrides,
  };
}

describe("getPendingSubmissions — Plan-Priority + Deadline", () => {
  it("sortiert Legend vor Pro vor Free (Plan-Priority)", async () => {
    const sameTime = new Date("2026-05-09T10:00:00Z");
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({
        id: "free-1",
        createdAt: sameTime,
        user: { id: "u1", nickname: "a", plan: "free" },
      }),
      makeRow({
        id: "legend-1",
        createdAt: sameTime,
        user: { id: "u2", nickname: "b", plan: "legend" },
      }),
      makeRow({
        id: "pro-1",
        createdAt: sameTime,
        user: { id: "u3", nickname: "c", plan: "pro" },
      }),
    ]);

    const result = await getPendingSubmissions();
    expect(result.map((r) => r.id)).toEqual(["legend-1", "pro-1", "free-1"]);
  });

  it("innerhalb gleicher Plan-Priority: älteste zuerst (FIFO)", async () => {
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({
        id: "legend-newer",
        createdAt: new Date("2026-05-09T12:00:00Z"),
        user: { id: "u1", nickname: "x", plan: "legend" },
      }),
      makeRow({
        id: "legend-older",
        createdAt: new Date("2026-05-09T08:00:00Z"),
        user: { id: "u2", nickname: "y", plan: "legend" },
      }),
    ]);

    const result = await getPendingSubmissions();
    expect(result.map((r) => r.id)).toEqual(["legend-older", "legend-newer"]);
  });

  it("berechnet deadlineAt = createdAt + 24h pro row", async () => {
    const created = new Date("2026-05-09T10:00:00Z");
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({ createdAt: created }),
    ]);

    const result = await getPendingSubmissions();
    const expectedDeadline = new Date(
      created.getTime() + ADMIN_APPROVAL_SLA_MS,
    );
    expect(result[0]!.deadlineAt.toISOString()).toBe(
      expectedDeadline.toISOString(),
    );
  });

  it("msUntilDeadline ist negativ wenn Submission überfällig (>24h alt)", async () => {
    // 30h alte Submission → 6h überfällig → ms negativ
    const created = new Date(Date.now() - 30 * 60 * 60 * 1000);
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({ createdAt: created }),
    ]);

    const result = await getPendingSubmissions();
    expect(result[0]!.msUntilDeadline).toBeLessThan(0);
  });

  it("planPriority fällt auf 0 zurück wenn user.plan unbekannt / null", async () => {
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({ user: null }),
    ]);
    const result = await getPendingSubmissions();
    expect(result[0]!.planPriority).toBe(0);
  });

  it("returned type='web' für Web-Submission", async () => {
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({ id: "web-sub", domain: "casino.de", type: "web" }),
    ]);
    const result = await getPendingSubmissions();
    expect(result[0]!.type).toBe("web");
  });

  it("returned type='mail_domain' für Mail-Submission", async () => {
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({
        id: "mail-sub",
        domain: "mailing.casino-affiliate.com",
        type: "mail_domain",
      }),
    ]);
    const result = await getPendingSubmissions();
    expect(result[0]!.type).toBe("mail_domain");
  });

  it("type ist im Response-Objekt vorhanden (passthrough)", async () => {
    prismaMock.domainSubmission.findMany.mockResolvedValueOnce([
      makeRow({ type: "mail_domain" }),
    ]);
    const result = await getPendingSubmissions();
    expect(Object.prototype.hasOwnProperty.call(result[0], "type")).toBe(true);
  });
});
