import { describe, it, expect, beforeEach, vi } from 'vitest';
import { RoleService } from '../../src/services/role.service';
import { Role } from '../../src/entities/role.entity';
import { DataSource, Repository } from 'typeorm';

// Mock DataSource
const mockDataSource = {
  getRepository: vi.fn()
} as unknown as DataSource;

// Mock repository
const mockRepository = {
  findOneBy: vi.fn(),
  findOne: vi.fn()
} as unknown as Repository<Role>;

describe('RoleService', () => {
  let roleService: RoleService;

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

    // Setup mock repository
    vi.mocked(mockDataSource.getRepository).mockReturnValue(mockRepository);

    roleService = new RoleService(mockDataSource);
  });

  describe('getRoleByName', () => {
    it('should return role by name', async () => {
      const mockRole = {
        id: 1,
        name: 'admin',
        description: 'Administrator role',
        permissions: ['user:create', 'user:delete']
      } as Role;

      vi.mocked(mockRepository.findOneBy).mockResolvedValue(mockRole);

      const result = await roleService.getRoleByName('admin');

      expect(mockRepository.findOneBy).toHaveBeenCalledWith({ name: 'admin' });
      expect(result).toEqual(mockRole);
    });

    it('should return null when role not found', async () => {
      vi.mocked(mockRepository.findOneBy).mockResolvedValue(null);

      const result = await roleService.getRoleByName('nonexistent');

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

  describe('checkPermission', () => {
    it('should return true when role has permission', async () => {
      const mockRole = {
        id: 1,
        name: 'admin',
        permissions: ['user:create', 'user:delete']
      } as Role;

      vi.mocked(mockRepository.findOne).mockResolvedValue(mockRole);

      const result = await roleService.checkPermission(1, 'user:create');

      expect(result).toBe(true);
    });

    it('should return false when role does not have permission', async () => {
      const mockRole = {
        id: 1,
        name: 'admin',
        permissions: ['user:create', 'user:delete']
      } as Role;

      vi.mocked(mockRepository.findOne).mockResolvedValue(mockRole);

      const result = await roleService.checkPermission(1, 'user:update');

      expect(result).toBe(false);
    });

    it('should return false when role not found', async () => {
      vi.mocked(mockRepository.findOne).mockResolvedValue(null);

      const result = await roleService.checkPermission(999, 'user:create');

      expect(result).toBe(false);
    });
  });

  // Test inherited methods from GenericCrudService
  describe('inherited methods', () => {
    it('should have getById method', () => {
      expect(roleService.getById).toBeDefined();
    });

    it('should have getList method', () => {
      expect(roleService.getList).toBeDefined();
    });

    it('should have create method', () => {
      expect(roleService.create).toBeDefined();
    });

    it('should have update method', () => {
      expect(roleService.update).toBeDefined();
    });

    it('should have delete method', () => {
      expect(roleService.delete).toBeDefined();
    });
  });
});