import { describe, it, expect, beforeEach, vi } from "vitest";
import { Test, TestingModule } from "@nestjs/testing";
import { AuthService } from "./auth.service";
import { PrismaService } from "../prisma/prisma.service";

describe("AuthService", () => {
  let service: AuthService;
  let prisma: PrismaService;

  const mockPrismaService = {
    user: {
      findUnique: vi.fn(),
    },
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        AuthService,
        {
          provide: PrismaService,
          useValue: mockPrismaService,
        },
      ],
    }).compile();

    service = module.get<AuthService>(AuthService);
    prisma = module.get<PrismaService>(PrismaService);

    vi.clearAllMocks();
  });

  describe("getAuth", () => {
    it("should return BetterAuth instance", () => {
      const auth = service.getAuth();
      expect(auth).toBeDefined();
      expect(auth.handler).toBeDefined();
    });
  });

  describe("getUserById", () => {
    const mockUser = {
      id: "user-123",
      email: "test@example.com",
      name: "Test User",
      authProviderId: "auth-123",
    };

    it("should get user by ID", async () => {
      mockPrismaService.user.findUnique.mockResolvedValue(mockUser);

      const result = await service.getUserById("user-123");

      expect(result).toEqual(mockUser);
      expect(mockPrismaService.user.findUnique).toHaveBeenCalledWith({
        where: { id: "user-123" },
        select: {
          id: true,
          email: true,
          name: true,
          authProviderId: true,
        },
      });
    });
  });

  describe("getUserByEmail", () => {
    const mockUser = {
      id: "user-123",
      email: "test@example.com",
      name: "Test User",
      authProviderId: "auth-123",
    };

    it("should get user by email", async () => {
      mockPrismaService.user.findUnique.mockResolvedValue(mockUser);

      const result = await service.getUserByEmail("test@example.com");

      expect(result).toEqual(mockUser);
      expect(mockPrismaService.user.findUnique).toHaveBeenCalledWith({
        where: { email: "test@example.com" },
        select: {
          id: true,
          email: true,
          name: true,
          authProviderId: true,
        },
      });
    });
  });

  describe("verifySession", () => {
    const mockSessionData = {
      user: {
        id: "user-123",
        email: "test@example.com",
        name: "Test User",
      },
      session: {
        id: "session-123",
        token: "test-token",
      },
    };

    it("should return session data for valid token", async () => {
      const auth = service.getAuth();
      const mockGetSession = vi.fn().mockResolvedValue(mockSessionData);
      auth.api = { getSession: mockGetSession } as any;

      const result = await service.verifySession("valid-token");

      expect(result).toEqual(mockSessionData);
      expect(mockGetSession).toHaveBeenCalledWith({
        headers: {
          authorization: "Bearer valid-token",
        },
      });
    });

    it("should return null for invalid session", async () => {
      const auth = service.getAuth();
      const mockGetSession = vi.fn().mockResolvedValue(null);
      auth.api = { getSession: mockGetSession } as any;

      const result = await service.verifySession("invalid-token");

      expect(result).toBeNull();
    });

    it("should return null and log error on verification failure", async () => {
      const auth = service.getAuth();
      const mockGetSession = vi.fn().mockRejectedValue(new Error("Verification failed"));
      auth.api = { getSession: mockGetSession } as any;

      const result = await service.verifySession("error-token");

      expect(result).toBeNull();
    });
  });
});
