import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

import 'package:superport_v2/core/network/api_error.dart';
import 'package:superport_v2/core/network/failure.dart';
import 'package:superport_v2/features/inventory/outbound/presentation/controllers/outbound_controller.dart';
import 'package:superport_v2/features/inventory/transactions/domain/entities/stock_transaction.dart';
import 'package:superport_v2/features/inventory/transactions/domain/entities/stock_transaction_input.dart';
import 'package:superport_v2/features/inventory/transactions/domain/repositories/stock_transaction_repository.dart';
import 'package:superport_v2/features/inventory/lookups/domain/repositories/inventory_lookup_repository.dart';

class _MockStockTransactionRepository extends Mock
    implements StockTransactionRepository {}

class _MockInventoryLookupRepository extends Mock
    implements InventoryLookupRepository {}

class _MockTransactionLineRepository extends Mock
    implements TransactionLineRepository {}

class _MockTransactionCustomerRepository extends Mock
    implements TransactionCustomerRepository {}

void main() {
  group('OutboundController', () {
    late StockTransactionRepository transactionRepository;
    late InventoryLookupRepository lookupRepository;
    late TransactionLineRepository lineRepository;
    late TransactionCustomerRepository customerRepository;
    late OutboundController controller;

    setUpAll(() {
      registerFallbackValue(
        StockTransactionCreateInput(
          transactionTypeId: 0,
          transactionStatusId: 0,
          warehouseId: 0,
          transactionDate: DateTime(2000, 1, 1),
          createdById: 0,
          approval: StockTransactionApprovalInput(requestedById: 0),
        ),
      );
      registerFallbackValue(
        StockTransactionUpdateInput(transactionStatusId: 0),
      );
      registerFallbackValue(StockTransactionListFilter());
    });

    setUp(() {
      transactionRepository = _MockStockTransactionRepository();
      lookupRepository = _MockInventoryLookupRepository();
      lineRepository = _MockTransactionLineRepository();
      customerRepository = _MockTransactionCustomerRepository();
      controller = OutboundController(
        transactionRepository: transactionRepository,
        lineRepository: lineRepository,
        customerRepository: customerRepository,
        lookupRepository: lookupRepository,
      );
    });

    test('createTransaction은 레코드를 추가한다', () async {
      final transaction = _buildTransaction();
      when(
        () => transactionRepository.create(any()),
      ).thenAnswer((_) async => transaction);

      final record = await controller.createTransaction(
        StockTransactionCreateInput(
          transactionTypeId: 1,
          transactionStatusId: 2,
          warehouseId: 3,
          transactionDate: DateTime(2024, 4, 1),
          createdById: 7,
          approval: StockTransactionApprovalInput(requestedById: 7),
        ),
        refreshAfter: false,
      );

      expect(record.id, equals(transaction.id));
      expect(controller.records.first.id, equals(transaction.id));
      expect(controller.approvalDraft?.requestedById, equals(7));
    });

    test('updateApprovalDraft와 clearApprovalDraft가 초안을 관리한다', () {
      final draft = StockTransactionApprovalInput(
        requestedById: 33,
        approvalStatusId: 4,
        note: '테스트',
      );

      controller.updateApprovalDraft(draft);

      expect(controller.approvalDraft?.requestedById, equals(33));
      expect(controller.approvalDraft?.approvalStatusId, equals(4));

      controller.clearApprovalDraft();

      expect(controller.approvalDraft, isNull);
    });

    test('completeTransaction은 레코드를 갱신하고 처리 상태를 추적한다', () async {
      final original = _buildTransaction();
      final completed = _buildTransaction(statusName: '출고완료');
      when(
        () => transactionRepository.create(any()),
      ).thenAnswer((_) async => original);
      when(
        () => transactionRepository.complete(any(), note: any(named: 'note')),
      ).thenAnswer((_) async => completed);

      await controller.createTransaction(
        StockTransactionCreateInput(
          transactionTypeId: 1,
          transactionStatusId: 2,
          warehouseId: 3,
          transactionDate: DateTime(2024, 4, 1),
          createdById: 7,
          approval: StockTransactionApprovalInput(requestedById: 7),
        ),
        refreshAfter: false,
      );

      final future = controller.completeTransaction(
        original.id!,
        refreshAfter: false,
      );

      expect(controller.processingTransactionIds.contains(original.id), isTrue);

      final record = await future;

      expect(record.status, equals('출고완료'));
      expect(controller.records.first.status, equals('출고완료'));
      expect(
        controller.processingTransactionIds.contains(original.id),
        isFalse,
      );
    });

    test('fetchTransactions 실패 시 Failure 메시지를 기록한다', () async {
      final exception = ApiException(
        code: ApiErrorCode.badRequest,
        message: '출고 데이터를 가져오지 못했습니다.',
        details: {
          'errors': {
            'warehouse_id': ['창고를 선택하세요.'],
          },
        },
      );

      when(
        () => transactionRepository.list(filter: any(named: 'filter')),
      ).thenThrow(exception);

      await controller.fetchTransactions(
        filter: StockTransactionListFilter(transactionTypeId: 1),
      );

      final failure = Failure.from(exception);
      expect(controller.errorMessage, equals(failure.describe()));
      expect(controller.records, isEmpty);
    });
  });
}

StockTransaction _buildTransaction({int id = 200, String statusName = '출고대기'}) {
  return StockTransaction(
    id: id,
    transactionNo: 'OUT-$id',
    transactionDate: DateTime(2024, 4, 1),
    type: StockTransactionType(id: 20, name: '출고'),
    status: StockTransactionStatus(id: 21, name: statusName),
    warehouse: StockTransactionWarehouse(id: 2, code: 'WH-2', name: '부산 센터'),
    createdBy: StockTransactionEmployee(
      id: 2,
      employeeNo: 'EMP-2',
      name: '출고 담당',
    ),
    lines: [
      StockTransactionLine(
        id: 10,
        lineNo: 1,
        product: StockTransactionProduct(id: 10, code: 'P-10', name: '출고 품목'),
        quantity: 3,
        unitPrice: 2500.0,
      ),
    ],
    customers: [
      StockTransactionCustomer(
        id: 1,
        customer: StockTransactionCustomerSummary(
          id: 100,
          code: 'C-1',
          name: '슈퍼포트 고객',
        ),
      ),
    ],
  );
}
