/**
 * Unit Tests for Social Accounts API
 * Files:
 *   app/api/social/accounts/route.ts (GET - list accounts)
 *   app/api/social/accounts/[id]/route.ts (DELETE - disconnect account)
 *
 * Tests account listing and disconnection endpoints.
 */

import { NextRequest } from "next/server";
import { GET } from "@/app/api/social/accounts/route";
import { DELETE } from "@/app/api/social/accounts/[id]/route";

// ── Mocks ────────────────────────────────────────────────────────────────

const mockAuth = jest.fn();
jest.mock("@/lib/auth", () => ({
  auth: () => mockAuth(),
}));

const mockGetAuthenticatedUser = jest.fn();
jest.mock("@/lib/utils/auth-helpers.util", () => ({
  getAuthenticatedUser: (...args: unknown[]) =>
    mockGetAuthenticatedUser(...args),
}));

const mockGetConnectedAccounts = jest.fn();
const mockGetAccountById = jest.fn();
const mockRevokeAccess = jest.fn();
jest.mock("@/lib/services/social-auth.service", () => ({
  getConnectedAccounts: (...args: unknown[]) =>
    mockGetConnectedAccounts(...args),
  getAccountById: (...args: unknown[]) => mockGetAccountById(...args),
  revokeAccess: (...args: unknown[]) => mockRevokeAccess(...args),
}));

jest.mock("@/lib/logger", () => ({
  logger: { info: jest.fn(), warn: jest.fn(), error: jest.fn() },
}));

// ── Helpers ──────────────────────────────────────────────────────────────

function makeRequest(path: string, method = "GET") {
  return new NextRequest(`http://localhost:9000${path}`, { method });
}

function makeParams(id: string) {
  return { params: Promise.resolve({ id }) };
}

const mockAccount = {
  id: "acc-1",
  userId: "user-1",
  platform: "FACEBOOK",
  platformAccountId: "page-123",
  accountName: "My Business Page",
  status: "CONNECTED",
  tokenExpiry: new Date(Date.now() + 60 * 24 * 60 * 60 * 1000),
  metadata: {},
  createdAt: new Date(),
  updatedAt: new Date(),
};

// ── Tests ────────────────────────────────────────────────────────────────

describe("GET /api/social/accounts", () => {
  beforeEach(() => jest.clearAllMocks());

  it("returns 401 when user is not authenticated", async () => {
    mockGetAuthenticatedUser.mockResolvedValue(null);

    const res = await GET(makeRequest("/api/social/accounts"));
    const json = await res.json();

    expect(res.status).toBe(401);
    expect(json.success).toBe(false);
  });

  it("returns list of connected accounts", async () => {
    mockGetAuthenticatedUser.mockResolvedValue({ userId: "user-1" });
    mockGetConnectedAccounts.mockResolvedValue([
      mockAccount,
      { ...mockAccount, id: "acc-2", platform: "INSTAGRAM" },
    ]);

    const res = await GET(makeRequest("/api/social/accounts"));
    const json = await res.json();

    expect(res.status).toBe(200);
    expect(json.success).toBe(true);
    expect(json.data).toHaveLength(2);
    expect(json.data[0].platform).toBe("FACEBOOK");
    expect(json.data[1].platform).toBe("INSTAGRAM");
  });

  it("returns empty array when no accounts connected", async () => {
    mockGetAuthenticatedUser.mockResolvedValue({ userId: "user-1" });
    mockGetConnectedAccounts.mockResolvedValue([]);

    const res = await GET(makeRequest("/api/social/accounts"));
    const json = await res.json();

    expect(res.status).toBe(200);
    expect(json.success).toBe(true);
    expect(json.data).toEqual([]);
  });

  it("returns 500 when service throws", async () => {
    mockGetAuthenticatedUser.mockResolvedValue({ userId: "user-1" });
    mockGetConnectedAccounts.mockRejectedValue(new Error("DB error"));

    const res = await GET(makeRequest("/api/social/accounts"));
    const json = await res.json();

    expect(res.status).toBe(500);
    expect(json.success).toBe(false);
  });
});

describe("DELETE /api/social/accounts/[id]", () => {
  beforeEach(() => jest.clearAllMocks());

  it("returns 401 when not authenticated", async () => {
    mockAuth.mockResolvedValue(null);

    const res = await DELETE(
      makeRequest("/api/social/accounts/acc-1", "DELETE"),
      makeParams("acc-1"),
    );

    expect(res.status).toBe(401);
  });

  it("returns 404 when account not found", async () => {
    mockAuth.mockResolvedValue({ user: { id: "user-1" } });
    mockGetAccountById.mockResolvedValue(null);

    const res = await DELETE(
      makeRequest("/api/social/accounts/fake-id", "DELETE"),
      makeParams("fake-id"),
    );
    const json = await res.json();

    expect(res.status).toBe(404);
    expect(json.error).toBe("Account not found");
  });

  it("disconnects account and returns success", async () => {
    mockAuth.mockResolvedValue({ user: { id: "user-1" } });
    mockGetAccountById.mockResolvedValue(mockAccount);
    mockRevokeAccess.mockResolvedValue(undefined);

    const res = await DELETE(
      makeRequest("/api/social/accounts/acc-1", "DELETE"),
      makeParams("acc-1"),
    );
    const json = await res.json();

    expect(res.status).toBe(200);
    expect(json.success).toBe(true);
    expect(json.message).toBe("Account disconnected");
    expect(mockRevokeAccess).toHaveBeenCalledWith("acc-1");
  });

  it("verifies account belongs to authenticated user", async () => {
    mockAuth.mockResolvedValue({ user: { id: "user-1" } });
    mockGetAccountById.mockResolvedValue(mockAccount);
    mockRevokeAccess.mockResolvedValue(undefined);

    await DELETE(
      makeRequest("/api/social/accounts/acc-1", "DELETE"),
      makeParams("acc-1"),
    );

    expect(mockGetAccountById).toHaveBeenCalledWith("acc-1", "user-1");
  });

  it("returns 500 when revokeAccess throws", async () => {
    mockAuth.mockResolvedValue({ user: { id: "user-1" } });
    mockGetAccountById.mockResolvedValue(mockAccount);
    mockRevokeAccess.mockRejectedValue(new Error("Meta API error"));

    const res = await DELETE(
      makeRequest("/api/social/accounts/acc-1", "DELETE"),
      makeParams("acc-1"),
    );
    const json = await res.json();

    expect(res.status).toBe(500);
    expect(json.success).toBe(false);
  });
});
