import { TestBed } from '@angular/core/testing';
import { of, NEVER } from 'rxjs';
import { BranchService } from './branch.service';
import { StockService, BranchDTO } from '@generated/swagger/inventory-api';

/**
 * Unit tests for BranchService.
 * Tests the service's ability to fetch default branch information.
 *
 * @group unit
 * @group services
 */
describe('BranchService', () => {
  let service: BranchService;
  let mockStockService: jest.Mocked<StockService>;

  const mockBranch: any = {
    id: 42,
    name: 'Test Branch',
    address: '123 Test St',
    branchType: 1,
    branchNumber: 'BR001',
    changed: '2024-01-01',
    created: '2024-01-01',
    isDefault: true,
    isOnline: true,
    key: 'test-branch',
    label: 'Test Branch Label',
    pId: 1,
    shortName: 'TB',
    status: 1,
    version: 1,
  };

  beforeEach(() => {
    // Create a fresh mock for each test to ensure isolation
    mockStockService = {
      StockCurrentBranch: jest.fn(),
    } as unknown as jest.Mocked<StockService>;

    TestBed.configureTestingModule({
      providers: [
        BranchService,
        { provide: StockService, useValue: mockStockService },
      ],
    });

    service = TestBed.inject(BranchService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  describe('getDefaultBranch', () => {
    it('should fetch default branch successfully', async () => {
      // Arrange
      const mockResponse: any = {
        error: false,
        result: mockBranch,
      };
      mockStockService.StockCurrentBranch.mockReturnValue(of(mockResponse));

      // Act
      const result = await service.getDefaultBranch();

      // Assert
      expect(result).toEqual(mockBranch);
      expect(mockStockService.StockCurrentBranch).toHaveBeenCalledWith();
    });

    it('should throw error if API response contains error', async () => {
      // Arrange
      const mockResponse: any = {
        error: true,
        message: 'API Error',
        result: undefined,
      };
      mockStockService.StockCurrentBranch.mockReturnValue(of(mockResponse));

      // Act & Assert
      await expect(service.getDefaultBranch()).rejects.toThrow();
    });

    it('should handle abortSignal', async () => {
      // Arrange
      mockStockService.StockCurrentBranch.mockReturnValue(NEVER);
      const abortController = new AbortController();

      // Act
      const promise = service.getDefaultBranch(abortController.signal);
      const timeout = new Promise((_, reject) =>
        setTimeout(() => reject(new Error('Timeout')), 100),
      );

      // Assert
      await expect(Promise.race([promise, timeout])).rejects.toThrow('Timeout');
    });

    it('should return branch with all properties', async () => {
      // Arrange
      const mockResponse: any = {
        error: false,
        result: mockBranch,
      };
      mockStockService.StockCurrentBranch.mockReturnValue(of(mockResponse));

      // Act
      const result = await service.getDefaultBranch();

      // Assert
      expect(result.id).toBe(42);
      expect(result.name).toBe('Test Branch');
      expect(result.isDefault).toBe(true);
      expect(result.isOnline).toBe(true);
      expect(result.branchNumber).toBe('BR001');
    });
  });
});
