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

import 'package:superport_v2/core/network/api_client.dart';
import 'package:superport_v2/features/inventory/transactions/data/repositories/transaction_line_repository_remote.dart';
import 'package:superport_v2/features/inventory/transactions/domain/entities/stock_transaction_input.dart';

class _MockApiClient extends Mock implements ApiClient {}

void main() {
  late ApiClient apiClient;
  late TransactionLineRepositoryRemote repository;

  setUpAll(() {
    registerFallbackValue(Options());
    registerFallbackValue(CancelToken());
  });

  setUp(() {
    apiClient = _MockApiClient();
    repository = TransactionLineRepositoryRemote(apiClient: apiClient);
  });

  test('addLines는 거래 ID를 포함한 POST 요청을 보낸다', () async {
    const path = '/api/v1/stock-transactions/50/lines';
    when(
      () => apiClient.post<void>(
        path,
        data: any(named: 'data'),
        options: any(named: 'options'),
        cancelToken: any(named: 'cancelToken'),
      ),
    ).thenAnswer(
      (_) async => Response<void>(
        requestOptions: RequestOptions(path: path),
        statusCode: 204,
      ),
    );

    await repository.addLines(50, [
      TransactionLineCreateInput(
        lineNo: 2,
        productId: 44,
        quantity: 5,
        unitPrice: 1500,
      ),
    ]);

    final payload =
        verify(
              () => apiClient.post<void>(
                captureAny(),
                data: captureAny(named: 'data'),
                options: any(named: 'options'),
                cancelToken: any(named: 'cancelToken'),
              ),
            ).captured[1]
            as Map<String, dynamic>;

    expect(payload['id'], 50);
    expect(payload['lines'], isA<List>());
  });

  test('updateLines는 PATCH 요청을 사용한다', () async {
    const path = '/api/v1/stock-transactions/50/lines';
    when(
      () => apiClient.patch<void>(
        path,
        data: any(named: 'data'),
        options: any(named: 'options'),
        cancelToken: any(named: 'cancelToken'),
      ),
    ).thenAnswer(
      (_) async => Response<void>(
        requestOptions: RequestOptions(path: path),
        statusCode: 204,
      ),
    );

    await repository.updateLines(50, [
      TransactionLineUpdateInput(id: 101, quantity: 10),
    ]);

    verify(
      () => apiClient.patch<void>(
        path,
        data: any(named: 'data'),
        options: any(named: 'options'),
        cancelToken: any(named: 'cancelToken'),
      ),
    ).called(1);
  });

  test('deleteLine은 /transaction-lines/{id}를 호출한다', () async {
    const path = '/api/v1/transaction-lines/101';
    when(
      () => apiClient.delete<void>(
        path,
        data: any(named: 'data'),
        options: any(named: 'options'),
        cancelToken: any(named: 'cancelToken'),
      ),
    ).thenAnswer(
      (_) async => Response<void>(
        requestOptions: RequestOptions(path: path),
        statusCode: 204,
      ),
    );

    await repository.deleteLine(101);

    verify(
      () => apiClient.delete<void>(
        path,
        data: any(named: 'data'),
        options: any(named: 'options'),
        cancelToken: any(named: 'cancelToken'),
      ),
    ).called(1);
  });

  test('restoreLine은 복구 엔드포인트를 호출한다', () async {
    const path = '/api/v1/transaction-lines/101/restore';
    when(
      () => apiClient.post<void>(
        path,
        data: any(named: 'data'),
        options: any(named: 'options'),
        cancelToken: any(named: 'cancelToken'),
      ),
    ).thenAnswer(
      (_) async => Response<void>(
        requestOptions: RequestOptions(path: path),
        statusCode: 204,
      ),
    );

    await repository.restoreLine(101);

    verify(
      () => apiClient.post<void>(
        path,
        data: any(named: 'data'),
        options: any(named: 'options'),
        cancelToken: any(named: 'cancelToken'),
      ),
    ).called(1);
  });
}
