import { ComponentFixture, TestBed } from '@angular/core/testing';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { Router } from '@angular/router';
import { Subject, of } from 'rxjs';
import { RemissionReturnReceiptCompleteComponent } from './remission-return-receipt-complete.component';
import {
  RemissionReturnReceiptService,
  RemissionStore,
} from '@isa/remission/data-access';
import { RemissionStartService } from '@isa/remission/shared/remission-start-dialog';
import { provideLoggerContext } from '@isa/core/logging';

// Mock the services
vi.mock('@isa/remission/data-access', async () => {
  const actual = await vi.importActual('@isa/remission/data-access');
  return {
    ...actual,
    RemissionReturnReceiptService: vi.fn(),
    RemissionStore: vi.fn(),
  };
});

vi.mock('@isa/remission/shared/remission-start-dialog', () => ({
  RemissionStartService: vi.fn(),
}));

vi.mock('@angular/router', () => ({
  Router: vi.fn(),
}));

// Mock the dialog injection function
vi.mock('@isa/ui/dialog', () => ({
  injectConfirmationDialog: vi.fn(),
}));

// Mock the tab injection function
vi.mock('@isa/core/tabs', () => ({
  injectTabId: vi.fn(),
}));

describe('RemissionReturnReceiptCompleteComponent', () => {
  let component: RemissionReturnReceiptCompleteComponent;
  let fixture: ComponentFixture<RemissionReturnReceiptCompleteComponent>;
  let mockRemissionReturnReceiptService: any;
  let mockRemissionStartService: any;
  let mockRouter: any;
  let mockRemissionStore: any;
  let mockDialogRef: any;
  let mockInjectConfirmationDialog: any;
  let mockInjectTabId: any;

  beforeEach(async () => {
    // Reset all mocks before each test
    vi.clearAllMocks();

    // Create mock services
    mockRemissionReturnReceiptService = {
      completeReturnReceiptAndReturn: vi.fn(),
      completeReturnGroup: vi.fn(),
    };

    mockRemissionStartService = {
      startRemission: vi.fn(),
      assignPackage: vi.fn(),
    };

    mockRouter = {
      navigate: vi.fn().mockResolvedValue(true),
    };

    mockRemissionStore = {
      clearState: vi.fn(),
    };

    mockDialogRef = {
      closed: new Subject(),
    };

    // Mock the injected functions
    mockInjectConfirmationDialog = vi.fn().mockReturnValue(mockDialogRef);
    mockInjectTabId = vi.fn().mockReturnValue('test-tab-id');

    // Setup the mocks for the import functions
    const { injectConfirmationDialog } = await import('@isa/ui/dialog');
    const { injectTabId } = await import('@isa/core/tabs');
    vi.mocked(injectConfirmationDialog).mockReturnValue(
      mockInjectConfirmationDialog,
    );
    vi.mocked(injectTabId).mockReturnValue(mockInjectTabId);

    await TestBed.configureTestingModule({
      imports: [RemissionReturnReceiptCompleteComponent],
      providers: [
        {
          provide: RemissionReturnReceiptService,
          useValue: mockRemissionReturnReceiptService,
        },
        { provide: RemissionStartService, useValue: mockRemissionStartService },
        { provide: Router, useValue: mockRouter },
        { provide: RemissionStore, useValue: mockRemissionStore },
        provideLoggerContext({ component: 'Test' }),
      ],
    }).compileComponents();

    fixture = TestBed.createComponent(RemissionReturnReceiptCompleteComponent);
    component = fixture.componentInstance;

    // Set required inputs
    fixture.componentRef.setInput('returnId', 123);
    fixture.componentRef.setInput('receiptId', 456);
    fixture.componentRef.setInput('itemsLength', 5);
    fixture.componentRef.setInput('hasAssignedPackage', true);

    fixture.detectChanges();
  });

  describe('Component Setup', () => {
    it('should create', () => {
      expect(component).toBeTruthy();
    });

    it('should have correct initial values', () => {
      expect(component.returnId()).toBe(123);
      expect(component.receiptId()).toBe(456);
      expect(component.itemsLength()).toBe(5);
      expect(component.hasAssignedPackage()).toBe(true);
      expect(component.completingRemission()).toBe(false);
    });
  });

  describe('Component methods', () => {
    describe('completeSingleReturnReceipt', () => {
      it('should complete single return receipt successfully', async () => {
        // Arrange
        const mockReturn = { id: 123, returnGroup: 'RG001' };
        mockRemissionReturnReceiptService.completeReturnReceiptAndReturn.mockResolvedValue(
          mockReturn,
        );

        // Act
        const result = await component.completeSingleReturnReceipt();

        // Assert
        expect(
          mockRemissionReturnReceiptService.completeReturnReceiptAndReturn,
        ).toHaveBeenCalledWith({
          returnId: 123,
          receiptId: 456,
        });
        expect(mockRemissionStore.clearState).toHaveBeenCalled();
        expect(result).toEqual(mockReturn);
      });
    });

    describe('completeRemission', () => {
      it('should complete remission with package already assigned and no return group', async () => {
        // Arrange
        const mockReturn = { id: 123, returnGroup: null };
        mockRemissionReturnReceiptService.completeReturnReceiptAndReturn.mockResolvedValue(
          mockReturn,
        );

        const reloadDataSpy = vi.fn();
        component.reloadData.subscribe(reloadDataSpy);

        // Act
        await component.completeRemission();

        // Assert
        expect(component.completingRemission()).toBe(false);
        expect(mockRemissionStartService.assignPackage).not.toHaveBeenCalled();
        expect(mockInjectConfirmationDialog).not.toHaveBeenCalled();
        expect(reloadDataSpy).toHaveBeenCalled();
      });

      it('should complete remission without package assigned and assign package successfully', async () => {
        // Arrange
        fixture.componentRef.setInput('hasAssignedPackage', false);
        fixture.detectChanges();

        const mockReturn = { id: 123, returnGroup: null };
        mockRemissionStartService.assignPackage.mockResolvedValue(true);
        mockRemissionReturnReceiptService.completeReturnReceiptAndReturn.mockResolvedValue(
          mockReturn,
        );

        const reloadDataSpy = vi.fn();
        component.reloadData.subscribe(reloadDataSpy);

        // Act
        await component.completeRemission();

        // Assert
        expect(mockRemissionStartService.assignPackage).toHaveBeenCalledWith({
          returnId: 123,
          receiptId: 456,
        });
        expect(component.completingRemission()).toBe(false);
        expect(reloadDataSpy).toHaveBeenCalled();
      });

      it('should complete remission with return group and user confirms completion', async () => {
        // Arrange
        const mockReturn = { id: 123, returnGroup: 'RG001' };
        mockRemissionReturnReceiptService.completeReturnReceiptAndReturn.mockResolvedValue(
          mockReturn,
        );
        mockRemissionReturnReceiptService.completeReturnGroup.mockResolvedValue(
          undefined,
        );

        // Mock dialog result with confirmed=true
        mockDialogRef.closed = of({ confirmed: true });

        const reloadDataSpy = vi.fn();
        component.reloadData.subscribe(reloadDataSpy);

        // Act
        await component.completeRemission();

        // Assert
        expect(mockInjectConfirmationDialog).toHaveBeenCalledWith({
          title: 'Wanne abgeschlossen',
          width: '30rem',
          data: {
            message: expect.stringContaining('Legen Sie abschließend den'),
            closeText: 'Neue Wanne',
            confirmText: 'Beenden',
          },
        });
        expect(
          mockRemissionReturnReceiptService.completeReturnGroup,
        ).toHaveBeenCalledWith({
          returnGroup: 'RG001',
        });
        expect(component.completingRemission()).toBe(false);
        expect(reloadDataSpy).toHaveBeenCalled();
      });

      it('should complete remission with return group and user chooses new container', async () => {
        // Arrange
        const mockReturn = { id: 123, returnGroup: 'RG001' };
        mockRemissionReturnReceiptService.completeReturnReceiptAndReturn.mockResolvedValue(
          mockReturn,
        );
        mockRemissionStartService.startRemission.mockResolvedValue(undefined);

        // Mock dialog result with confirmed=false (user chose "Neue Wanne")
        mockDialogRef.closed = of({ confirmed: false });

        const reloadDataSpy = vi.fn();
        component.reloadData.subscribe(reloadDataSpy);

        // Act
        await component.completeRemission();

        // Assert
        expect(mockInjectConfirmationDialog).toHaveBeenCalledWith({
          title: 'Wanne abgeschlossen',
          width: '30rem',
          data: {
            message: expect.stringContaining('Legen Sie abschließend den'),
            closeText: 'Neue Wanne',
            confirmText: 'Beenden',
          },
        });
        expect(mockRemissionStartService.startRemission).toHaveBeenCalledWith(
          'RG001',
        );
        expect(mockRouter.navigate).toHaveBeenCalledWith([
          '/',
          'test-tab-id',
          'remission',
        ]);
        expect(component.completingRemission()).toBe(false);
        expect(reloadDataSpy).toHaveBeenCalled();
      });

      it('should prevent multiple completion attempts', async () => {
        // Arrange
        component.completingRemission.set(true);
        const reloadDataSpy = vi.fn();
        component.reloadData.subscribe(reloadDataSpy);

        // Act
        await component.completeRemission();

        // Assert
        expect(
          mockRemissionReturnReceiptService.completeReturnReceiptAndReturn,
        ).not.toHaveBeenCalled();
        expect(reloadDataSpy).not.toHaveBeenCalled();
      });

      it('should emit reloadData on successful completion', async () => {
        // Arrange
        const mockReturn = { id: 123, returnGroup: null };
        mockRemissionReturnReceiptService.completeReturnReceiptAndReturn.mockResolvedValue(
          mockReturn,
        );

        const reloadDataSpy = vi.fn();
        component.reloadData.subscribe(reloadDataSpy);

        // Act
        await component.completeRemission();

        // Assert
        expect(reloadDataSpy).toHaveBeenCalled();
      });
    });

    describe('navigateToRemissionList', () => {
      it('should navigate to remission list', async () => {
        // Act
        await component.navigateToRemissionList();

        // Assert
        expect(mockRouter.navigate).toHaveBeenCalledWith([
          '/',
          'test-tab-id',
          'remission',
        ]);
      });
    });
  });
});
