import { describe, it, expect, beforeEach, vi } from 'vitest';
import { GET, POST } from '../route';
import { documentService } from '@/lib/services/documentService';
import { getServerSession } from 'next-auth';

vi.mock('@/lib/services/documentService', () => ({
  documentService: {
    getDocuments: vi.fn(),
    createDocument: vi.fn(),
  },
}));

vi.mock('next-auth', () => ({
  getServerSession: vi.fn(),
}));

vi.mock('../auth/[...nextauth]/route', () => ({
  authOptions: {},
}));

describe('GET /api/documents', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('debería retornar 401 si no hay sesión', async () => {
    vi.mocked(getServerSession).mockResolvedValue(null);

    const response = await GET({ nextUrl: { searchParams: { get: vi.fn() } } } as any);
    const data = await response.json();

    expect(response.status).toBe(401);
    expect(data.error).toBe('No autenticado');
  });

  it('debería retornar documentos para usuario autenticado', async () => {
    const mockSession = {
      user: { id: 'user1', role: 'USER' },
    };

    const mockDocuments = [
      {
        id: '1',
        fileName: 'test.pdf',
        fileUrl: '/api/files/test.pdf',
        ownerId: 'user1',
        extractedData: { nombre: 'Test' },
        owner: { id: 'user1', name: 'User', username: 'user1' },
        createdAt: new Date(),
        updatedAt: new Date(),
        categoryId: null,
      },
    ];

    vi.mocked(getServerSession).mockResolvedValue(mockSession as any);
    vi.mocked(documentService.getDocuments).mockResolvedValue(mockDocuments as any);

    const mockSearchParams = {
      get: vi.fn((param) => {
        if (param === 'q') return undefined;
        if (param === 'categoryId') return undefined;
        return null;
      }),
    };

    const response = await GET({ nextUrl: { searchParams: mockSearchParams } } as any);
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data.success).toBe(true);
    expect(data.documents).toHaveLength(1);
    expect(documentService.getDocuments).toHaveBeenCalledWith({
      query: undefined,
      categoryId: undefined,
      userId: 'user1',
      role: 'USER',
    });
  });

  it('debería pasar los filtros de búsqueda al service', async () => {
    const mockSession = { user: { id: 'user1', role: 'ADMIN' } };
    const mockSearchParams = {
      get: vi.fn((param) => {
        if (param === 'q') return 'factura';
        if (param === 'categoryId') return 'cat1';
        return null;
      }),
    };

    vi.mocked(getServerSession).mockResolvedValue(mockSession as any);
    vi.mocked(documentService.getDocuments).mockResolvedValue([]);

    await GET({ nextUrl: { searchParams: mockSearchParams } } as any);

    expect(documentService.getDocuments).toHaveBeenCalledWith({
      query: 'factura',
      categoryId: 'cat1',
      userId: 'user1',
      role: 'ADMIN',
    });
  });
});

describe('POST /api/documents', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('debería retornar 401 si no hay sesión', async () => {
    vi.mocked(getServerSession).mockResolvedValue(null);

    const response = await POST({ json: vi.fn() } as any);
    const data = await response.json();

    expect(response.status).toBe(401);
    expect(data.error).toBe('No autenticado');
  });

  it('debería retornar 400 si faltan datos requeridos', async () => {
    const mockSession = { user: { id: 'user1' } };
    vi.mocked(getServerSession).mockResolvedValue(mockSession as any);

    const mockJson = vi.fn().mockResolvedValue({
      fileName: 'test.pdf',
      // Faltan fileData, mimeType, ownerId
    });

    const response = await POST({ json: mockJson } as any);
    const data = await response.json();

    expect(response.status).toBe(400);
    expect(data.error).toContain('Faltan datos requeridos');
  });

  it('debería retornar 403 si usuario intenta guardar para otro', async () => {
    const mockSession = { user: { id: 'user1', role: 'USER' } };
    vi.mocked(getServerSession).mockResolvedValue(mockSession as any);

    const mockJson = vi.fn().mockResolvedValue({
      fileName: 'test.pdf',
      fileData: 'base64data',
      mimeType: 'application/pdf',
      ownerId: 'user2', // Diferente al usuario de sesión
    });

    const response = await POST({ json: mockJson } as any);
    const data = await response.json();

    expect(response.status).toBe(403);
    expect(data.error).toContain('No tienes permisos');
  });

  it('debería crear documento exitosamente', async () => {
    const mockSession = { user: { id: 'user1', role: 'USER' } };
    vi.mocked(getServerSession).mockResolvedValue(mockSession as any);

    const requestBody = {
      fileName: 'test.pdf',
      fileData: 'base64data',
      mimeType: 'application/pdf',
      extractedData: { nombre: 'Test' },
      ownerId: 'user1',
      categoryId: 'cat1',
    };

    const mockJson = vi.fn().mockResolvedValue(requestBody);

    vi.mocked(documentService.createDocument).mockResolvedValue({
      id: 'doc1',
    });

    const response = await POST({ json: mockJson } as any);
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data.success).toBe(true);
    expect(data.documentId).toBe('doc1');
    expect(documentService.createDocument).toHaveBeenCalledWith(requestBody);
  });

  it('debería permitir ADMIN guardar para cualquier usuario', async () => {
    const mockSession = { user: { id: 'admin1', role: 'ADMIN' } };
    vi.mocked(getServerSession).mockResolvedValue(mockSession as any);

    const requestBody = {
      fileName: 'test.pdf',
      fileData: 'base64data',
      mimeType: 'application/pdf',
      extractedData: {},
      ownerId: 'user2', // ADMIN puede guardar para otros
    };

    vi.mocked(documentService.createDocument).mockResolvedValue({ id: 'doc1' });

    const response = await POST({ json: vi.fn().mockResolvedValue(requestBody) } as any);
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data.success).toBe(true);
  });
});
