import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';
import 'package:mocktail/mocktail.dart';
import 'package:shadcn_ui/shadcn_ui.dart';

import 'package:superport_v2/core/common/models/paginated_result.dart';
import 'package:superport_v2/features/inventory/summary/application/inventory_service.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_counterparty.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_detail.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_event.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_filters.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_product.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_summary.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_summary_list_result.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_vendor.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_warehouse.dart';
import 'package:superport_v2/features/inventory/summary/domain/entities/inventory_warehouse_balance.dart';
import 'package:superport_v2/features/inventory/summary/domain/repositories/inventory_repository.dart';
import 'package:superport_v2/features/inventory/summary/presentation/pages/inventory_summary_page.dart';
import 'package:superport_v2/features/masters/warehouse/domain/entities/warehouse.dart';
import 'package:superport_v2/features/masters/warehouse/domain/repositories/warehouse_repository.dart';

class _MockInventoryRepository extends Mock implements InventoryRepository {}

class _MockWarehouseRepository extends Mock implements WarehouseRepository {}

Widget _buildApp(Widget child) {
  return MaterialApp(
    home: ShadTheme(
      data: ShadThemeData(
        colorScheme: const ShadSlateColorScheme.light(),
        brightness: Brightness.light,
      ),
      child: Scaffold(body: child),
    ),
  );
}

void _registerDependencies({
  required InventoryRepository inventoryRepository,
  required WarehouseRepository warehouseRepository,
}) {
  GetIt.I.registerSingleton<InventoryService>(
    InventoryService(repository: inventoryRepository),
  );
  GetIt.I.registerSingleton<WarehouseRepository>(warehouseRepository);
}

void _stubWarehouseList(_MockWarehouseRepository repository) {
  when(
    () => repository.list(
      page: any(named: 'page'),
      pageSize: any(named: 'pageSize'),
      query: any(named: 'query'),
      isActive: any(named: 'isActive'),
      includeZipcode: any(named: 'includeZipcode'),
    ),
  ).thenAnswer((invocation) async {
    final page = invocation.namedArguments[const Symbol('page')] as int? ?? 1;
    final items = page == 1
        ? [Warehouse(id: 1, warehouseCode: 'WH-001', warehouseName: '본사 창고')]
        : const <Warehouse>[];
    return PaginatedResult<Warehouse>(
      items: items,
      page: page,
      pageSize:
          invocation.namedArguments[const Symbol('pageSize')] as int? ?? 20,
      total: items.length,
    );
  });
}

InventorySummaryListResult _buildSummaryResult() {
  final product = InventoryProduct(
    id: 10,
    code: 'INV-10',
    name: '테스트 장비',
    vendor: const InventoryVendor(id: 55, name: '테스트 벤더'),
  );
  final warehouse = InventoryWarehouse(id: 1, code: 'WH-001', name: '본사');
  final summary = InventorySummary(
    product: product,
    totalQuantity: 120,
    warehouseBalances: [
      InventoryWarehouseBalance(warehouse: warehouse, quantity: 80),
      InventoryWarehouseBalance(
        warehouse: InventoryWarehouse(id: 2, code: 'WH-002', name: '보관창고'),
        quantity: 40,
      ),
    ],
    recentEvent: InventoryEvent(
      eventId: 900,
      eventKind: 'receipt',
      eventLabel: '입고',
      deltaQuantity: 30,
      occurredAt: DateTime.utc(2025, 1, 3, 9, 0),
      counterparty: const InventoryCounterparty(
        type: InventoryCounterpartyType.vendor,
        name: 'QA 파트너',
      ),
      warehouse: warehouse,
    ),
    updatedAt: DateTime.utc(2025, 1, 3, 9, 15),
    lastRefreshedAt: DateTime.utc(2025, 1, 3, 9, 5),
  );
  return InventorySummaryListResult(
    result: PaginatedResult<InventorySummary>(
      items: [summary],
      page: 1,
      pageSize: 50,
      total: 1,
    ),
    lastRefreshedAt: summary.lastRefreshedAt,
  );
}

InventoryDetail _buildDetail() {
  final warehouse1 = InventoryWarehouse(id: 1, code: 'WH-001', name: '본사');
  final warehouse2 = InventoryWarehouse(id: 2, code: 'WH-002', name: '보관창고');
  return InventoryDetail(
    product: InventoryProduct(
      id: 10,
      code: 'INV-10',
      name: '테스트 장비',
      vendor: const InventoryVendor(id: 55, name: '테스트 벤더'),
    ),
    totalQuantity: 120,
    warehouseBalances: [
      InventoryWarehouseBalance(warehouse: warehouse1, quantity: 80),
      InventoryWarehouseBalance(warehouse: warehouse2, quantity: 40),
    ],
    recentEvents: [
      InventoryEvent(
        eventId: 901,
        eventKind: 'receipt',
        eventLabel: '입고',
        deltaQuantity: 20,
        occurredAt: DateTime.utc(2025, 1, 3, 9, 10),
        counterparty: const InventoryCounterparty(
          type: InventoryCounterpartyType.vendor,
          name: 'QA 파트너',
        ),
        warehouse: warehouse1,
      ),
    ],
    updatedAt: DateTime.utc(2025, 1, 3, 9, 20),
    lastRefreshedAt: DateTime.utc(2025, 1, 3, 9, 5),
  );
}

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  setUpAll(() {
    registerFallbackValue(const InventorySummaryFilter());
    registerFallbackValue(const InventoryDetailFilter());
  });

  tearDown(() async {
    await GetIt.I.reset();
  });

  testWidgets('자동 새로고침 토글이 주기적 재조회 동작을 제어한다', (tester) async {
    final inventoryRepository = _MockInventoryRepository();
    final warehouseRepository = _MockWarehouseRepository();
    final summaryResult = _buildSummaryResult();
    final detail = _buildDetail();
    var listCallCount = 0;

    when(
      () => inventoryRepository.listSummaries(filter: any(named: 'filter')),
    ).thenAnswer((_) async {
      listCallCount += 1;
      return summaryResult;
    });
    when(
      () =>
          inventoryRepository.fetchDetail(any(), filter: any(named: 'filter')),
    ).thenAnswer((_) async => detail);
    _stubWarehouseList(warehouseRepository);
    _registerDependencies(
      inventoryRepository: inventoryRepository,
      warehouseRepository: warehouseRepository,
    );

    await tester.pumpWidget(
      _buildApp(
        InventorySummaryPage(routeUri: Uri(path: '/inventory/summary')),
      ),
    );
    await tester.pumpAndSettle();

    expect(listCallCount, 1);
    expect(find.text('테스트 장비'), findsOneWidget);
    expect(find.textContaining('마지막 리프레시'), findsOneWidget);
    expect(find.text('자동 새로고침'), findsOneWidget);

    await tester.pump(const Duration(seconds: 31));
    await tester.pump();

    expect(listCallCount, 2);

    await tester.tap(find.bySemanticsLabel('자동 새로고침 전환'));
    await tester.pumpAndSettle();

    await tester.pump(const Duration(seconds: 31));
    await tester.pump();

    expect(listCallCount, 2);
  });

  testWidgets('행을 탭하면 상세 시트에서 창고 차트와 최근 이벤트를 확인할 수 있다', (tester) async {
    final inventoryRepository = _MockInventoryRepository();
    final warehouseRepository = _MockWarehouseRepository();
    final summaryResult = _buildSummaryResult();
    final detail = _buildDetail();

    when(
      () => inventoryRepository.listSummaries(filter: any(named: 'filter')),
    ).thenAnswer((_) async => summaryResult);
    when(
      () =>
          inventoryRepository.fetchDetail(any(), filter: any(named: 'filter')),
    ).thenAnswer((_) async => detail);
    _stubWarehouseList(warehouseRepository);
    _registerDependencies(
      inventoryRepository: inventoryRepository,
      warehouseRepository: warehouseRepository,
    );

    await tester.pumpWidget(
      _buildApp(
        InventorySummaryPage(routeUri: Uri(path: '/inventory/summary')),
      ),
    );
    await tester.pumpAndSettle();

    await tester.tap(find.text('테스트 장비'));
    await tester.pumpAndSettle();

    expect(find.text('창고 잔량'), findsOneWidget);
    expect(find.byType(LinearProgressIndicator), findsWidgets);
    expect(find.text('최근 이벤트'), findsOneWidget);
    expect(find.textContaining('거래처: QA 파트너'), findsOneWidget);
  });

  testWidgets('권한 오류가 발생하면 경고 배너를 노출한다', (tester) async {
    final inventoryRepository = _MockInventoryRepository();
    final warehouseRepository = _MockWarehouseRepository();

    when(
      () => inventoryRepository.listSummaries(filter: any(named: 'filter')),
    ).thenThrow(Exception('재고 조회 권한이 없습니다.'));
    _stubWarehouseList(warehouseRepository);
    _registerDependencies(
      inventoryRepository: inventoryRepository,
      warehouseRepository: warehouseRepository,
    );

    await tester.pumpWidget(
      _buildApp(
        InventorySummaryPage(routeUri: Uri(path: '/inventory/summary')),
      ),
    );
    await tester.pumpAndSettle();

    expect(find.textContaining('재고 조회 권한이 없습니다.'), findsOneWidget);
  });

  testWidgets('검색 적용 시 입력값이 필터에 반영된다', (tester) async {
    final inventoryRepository = _MockInventoryRepository();
    final warehouseRepository = _MockWarehouseRepository();
    final summaryResult = _buildSummaryResult();
    final detail = _buildDetail();
    final capturedFilters = <InventorySummaryFilter>[];

    when(
      () => inventoryRepository.listSummaries(filter: any(named: 'filter')),
    ).thenAnswer((invocation) async {
      final filter =
          invocation.namedArguments[const Symbol('filter')]
              as InventorySummaryFilter?;
      if (filter != null) {
        capturedFilters.add(filter);
      }
      return summaryResult;
    });
    when(
      () =>
          inventoryRepository.fetchDetail(any(), filter: any(named: 'filter')),
    ).thenAnswer((_) async => detail);
    _stubWarehouseList(warehouseRepository);
    _registerDependencies(
      inventoryRepository: inventoryRepository,
      warehouseRepository: warehouseRepository,
    );

    await tester.pumpWidget(
      _buildApp(
        InventorySummaryPage(routeUri: Uri(path: '/inventory/summary')),
      ),
    );
    await tester.pumpAndSettle();

    expect(capturedFilters, isNotEmpty);

    await tester.enterText(
      find.byKey(const Key('inventory_filter_query_field')),
      '카메라',
    );
    await tester.pump();

    await tester.tap(find.byKey(const Key('inventory_filter_apply')));
    await tester.pumpAndSettle();

    expect(capturedFilters.length, greaterThanOrEqualTo(2));
    final latest = capturedFilters.last;
    expect(latest.query, '카메라');
    expect(latest.page, 1);
  });

  testWidgets('목록이 비어 있으면 안내 문구를 노출한다', (tester) async {
    final inventoryRepository = _MockInventoryRepository();
    final warehouseRepository = _MockWarehouseRepository();
    final emptyResult = InventorySummaryListResult(
      result: PaginatedResult<InventorySummary>(
        items: const [],
        page: 1,
        pageSize: 50,
        total: 0,
      ),
      lastRefreshedAt: DateTime.utc(2025, 1, 3, 9, 0),
    );

    when(
      () => inventoryRepository.listSummaries(filter: any(named: 'filter')),
    ).thenAnswer((_) async => emptyResult);
    when(
      () =>
          inventoryRepository.fetchDetail(any(), filter: any(named: 'filter')),
    ).thenAnswer((_) async => _buildDetail());
    _stubWarehouseList(warehouseRepository);
    _registerDependencies(
      inventoryRepository: inventoryRepository,
      warehouseRepository: warehouseRepository,
    );

    await tester.pumpWidget(
      _buildApp(
        InventorySummaryPage(routeUri: Uri(path: '/inventory/summary')),
      ),
    );
    await tester.pumpAndSettle();

    expect(find.text('조건에 맞는 재고 데이터가 없습니다.'), findsOneWidget);
  });

  testWidgets('총 수량 헤더를 탭하면 정렬 파라미터가 토글된다', (tester) async {
    final inventoryRepository = _MockInventoryRepository();
    final warehouseRepository = _MockWarehouseRepository();
    final summaryResult = _buildSummaryResult();
    final detail = _buildDetail();
    final recordedFilters = <InventorySummaryFilter>[];

    when(
      () => inventoryRepository.listSummaries(filter: any(named: 'filter')),
    ).thenAnswer((invocation) async {
      final filter =
          invocation.namedArguments[const Symbol('filter')]
              as InventorySummaryFilter?;
      if (filter != null) {
        recordedFilters.add(filter);
      }
      return summaryResult;
    });
    when(
      () =>
          inventoryRepository.fetchDetail(any(), filter: any(named: 'filter')),
    ).thenAnswer((_) async => detail);
    _stubWarehouseList(warehouseRepository);
    _registerDependencies(
      inventoryRepository: inventoryRepository,
      warehouseRepository: warehouseRepository,
    );

    await tester.pumpWidget(
      _buildApp(
        InventorySummaryPage(routeUri: Uri(path: '/inventory/summary')),
      ),
    );
    await tester.pumpAndSettle();

    expect(recordedFilters, isNotEmpty);
    // 첫 정렬: 총 수량 헤더 탭 → 오름차순
    await tester.tap(find.text('총 수량').first);
    await tester.pumpAndSettle();
    final ascFilter = recordedFilters.last;
    expect(ascFilter.sort, 'total_quantity');
    expect(ascFilter.order, 'asc');

    // 두 번째 탭 → 내림차순
    await tester.tap(find.text('총 수량').first);
    await tester.pumpAndSettle();
    final descFilter = recordedFilters.last;
    expect(descFilter.sort, 'total_quantity');
    expect(descFilter.order, 'desc');
  });
}
