import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:feature_wordpress/feature_wordpress.dart';

/// A repository that always throws on [getProductDrafts] to exercise the
/// error state. Kept test-local to avoid broadening the public API.
class _FailingRepository implements ProductPublishingRepository {
  int loadAttempts = 0;

  @override
  Future<List<ProductDraft>> getProductDrafts() async {
    loadAttempts++;
    throw Exception('network error');
  }

  @override
  Future<ProductDraft> publishDraft(String id) async => throw UnimplementedError();

  @override
  Future<ProductDraft> updateProductStatus(String id, PublishStatus status) async =>
      throw UnimplementedError();

  @override
  Future<ProductDraft> updateProductPrice(String id, double price) async =>
      throw UnimplementedError();

  @override
  Future<ProductDraft> updateProductName(String id, String name) async =>
      throw UnimplementedError();

  @override
  Future<ProductDraft> updateProductDescription(String id, String description) async =>
      throw UnimplementedError();

  @override
  Future<ProductDraft> updateProductCategory(String id, String category) async =>
      throw UnimplementedError();

  // Stage 9C additions
  @override
  Future<ProductDraft> createProduct({
    required String name,
    required double price,
    String description = '',
    String sku = '',
    int? categoryId,
    PublishStatus status = PublishStatus.draft,
  }) async => throw UnimplementedError();

  @override
  Future<void> deleteProduct(String id, {bool force = false}) async => throw UnimplementedError();

  @override
  Future<ProductDraft> updateProductImages(String id, List<int> imageIds) async =>
      throw UnimplementedError();

  @override
  Future<List<ProductCategory>> getCategories() async => throw UnimplementedError();

  @override
  Future<ProductCategory> createCategory({required String name, int parentId = 0}) async =>
      throw UnimplementedError();

  @override
  Future<ProductCategory> updateCategory(int categoryId, {String? name, int? parentId}) async =>
      throw UnimplementedError();

  @override
  Future<void> deleteCategory(int categoryId, {bool force = true}) async =>
      throw UnimplementedError();

  @override
  Future<List<ProductImage>> getProductImages(String id) async => throw UnimplementedError();
}

void main() {
  group('ProductPublishingPage polish states', () {
    // ── Loading state ──────────────────────────────────────────────────────

    testWidgets('shows loading indicator with contextual text', (tester) async {
      // Use a narrow viewport to keep the layout simple.
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      final repository = FakeProductPublishingRepository();

      await tester.pumpWidget(
        MaterialApp(
          theme: buildKcTheme(),
          home: Scaffold(body: ProductPublishingPage(repository: repository)),
        ),
      );

      // Before pumpAndSettle — the controller is still loading.
      expect(find.byType(CircularProgressIndicator), findsOneWidget);
      expect(find.text('Loading products…'), findsOneWidget);

      // Let the load complete so the test tears down cleanly.
      await tester.pumpAndSettle();
    });

    // ── Error state ────────────────────────────────────────────────────────

    testWidgets('shows error state with retry button', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      final repository = _FailingRepository();

      await tester.pumpWidget(
        MaterialApp(
          theme: buildKcTheme(),
          home: Scaffold(body: ProductPublishingPage(repository: repository)),
        ),
      );
      await tester.pumpAndSettle();

      expect(find.text('Failed to load product drafts.'), findsOneWidget);
      expect(find.byIcon(Icons.error_outline), findsOneWidget);
      expect(find.text('Retry'), findsOneWidget);
      expect(repository.loadAttempts, 1);
    });

    testWidgets('retry button triggers a new load attempt', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      final repository = _FailingRepository();

      await tester.pumpWidget(
        MaterialApp(
          theme: buildKcTheme(),
          home: Scaffold(body: ProductPublishingPage(repository: repository)),
        ),
      );
      await tester.pumpAndSettle();

      expect(repository.loadAttempts, 1);

      await tester.tap(find.text('Retry'));
      await tester.pumpAndSettle();

      expect(repository.loadAttempts, 2);
    });

    // ── Empty list state (filtered to zero results) ────────────────────────

    testWidgets('shows empty state when filter yields no results', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      final repository = FakeProductPublishingRepository();

      // Use a search query that matches nothing.
      await tester.pumpWidget(
        MaterialApp(
          theme: buildKcTheme(),
          home: Scaffold(
            body: ProductPublishingPage(repository: repository, initialQuery: 'zzz_no_match_zzz'),
          ),
        ),
      );
      await tester.pumpAndSettle();

      expect(find.text('No products match your criteria.'), findsOneWidget);
      expect(find.byIcon(Icons.search_off), findsOneWidget);
    });

    // ── Product count header ───────────────────────────────────────────────

    testWidgets('shows product count header on narrow layout', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      final repository = FakeProductPublishingRepository();

      await tester.pumpWidget(
        MaterialApp(
          theme: buildKcTheme(),
          home: Scaffold(body: ProductPublishingPage(repository: repository)),
        ),
      );
      await tester.pumpAndSettle();

      // The fake repository has 6 products.
      expect(find.text('6 products'), findsOneWidget);
    });

    testWidgets('shows singular product count when filtered to one', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      final repository = FakeProductPublishingRepository();

      // "nightlight" matches exactly one product in the fake data.
      await tester.pumpWidget(
        MaterialApp(
          theme: buildKcTheme(),
          home: Scaffold(
            body: ProductPublishingPage(repository: repository, initialQuery: 'nightlight'),
          ),
        ),
      );
      await tester.pumpAndSettle();

      expect(find.text('1 product'), findsOneWidget);
    });

    // ── Empty selection placeholder (wide layout) ──────────────────────────

    testWidgets('shows selection placeholder with icon on wide layout', (tester) async {
      tester.view.physicalSize = const Size(1200, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      final repository = FakeProductPublishingRepository();

      // A query that matches nothing yields empty drafts + null selection.
      // On wide layout the Row renders both panes, so we can verify both
      // the empty-list and empty-selection placeholders.
      await tester.pumpWidget(
        MaterialApp(
          theme: buildKcTheme(),
          home: Scaffold(
            body: ProductPublishingPage(repository: repository, initialQuery: 'zzz_no_match_zzz'),
          ),
        ),
      );
      await tester.pumpAndSettle();

      // The empty-list state shows in the left pane.
      expect(find.text('No products match your criteria.'), findsOneWidget);

      // The empty-selection state shows in the right pane.
      expect(find.text('Select a product to preview'), findsOneWidget);
      expect(find.byIcon(Icons.touch_app_outlined), findsOneWidget);
    });
  });

  group('ProductPublishingPage multi-select bulk actions', () {
    Widget buildPage({FakeProductPublishingRepository? repo}) {
      return MaterialApp(
        theme: buildKcTheme(),
        home: Scaffold(
          body: ProductPublishingPage(repository: repo ?? FakeProductPublishingRepository()),
        ),
      );
    }

    testWidgets('multi-select bar shows Publish button', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      await tester.pumpWidget(buildPage());
      await tester.pumpAndSettle();

      // Activate multi-select by long-pressing the first product card's checkbox area.
      // The checkbox appears on the card — we toggle multi-select via the card's onMultiSelectToggle.
      // ProductDraftCard has a Checkbox when in multi-select mode, but multi-select is
      // triggered by tapping the checkbox. Since no items are selected initially,
      // the checkbox is shown as leading widget. Let's find checkboxes.
      final checkboxes = find.byType(Checkbox);
      expect(checkboxes, findsWidgets);

      // Tap first checkbox to enter multi-select mode.
      await tester.tap(checkboxes.first);
      await tester.pumpAndSettle();

      // Multi-select bar should appear with all three bulk action buttons.
      expect(find.text('Move to Draft'), findsOneWidget);
      expect(find.text('Publish'), findsOneWidget);
      expect(find.text('Submit for Review'), findsOneWidget);
      expect(find.text('1 selected'), findsOneWidget);
    });

    testWidgets('Publish button shows confirmation dialog', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      await tester.pumpWidget(buildPage());
      await tester.pumpAndSettle();

      // Activate multi-select.
      final checkboxes = find.byType(Checkbox);
      await tester.tap(checkboxes.first);
      await tester.pumpAndSettle();

      // Tap the Publish button.
      await tester.tap(find.text('Publish'));
      await tester.pumpAndSettle();

      // Confirmation dialog should appear.
      expect(find.text('Publish Products'), findsOneWidget);
      expect(find.text('Publish 1 product to the store?'), findsOneWidget);
      expect(find.text('Cancel'), findsOneWidget);
    });

    testWidgets('Submit for Review button shows confirmation dialog', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      await tester.pumpWidget(buildPage());
      await tester.pumpAndSettle();

      // Activate multi-select.
      final checkboxes = find.byType(Checkbox);
      await tester.tap(checkboxes.first);
      await tester.pumpAndSettle();

      // Tap the Submit for Review button.
      await tester.tap(find.text('Submit for Review'));
      await tester.pumpAndSettle();

      // Confirmation dialog should appear.
      expect(find.text('Submit for Review'), findsWidgets); // button + dialog title
      expect(find.text('Submit 1 product for review?'), findsOneWidget);
      expect(find.text('Cancel'), findsOneWidget);
    });

    testWidgets('cancelling publish dialog does not change statuses', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      await tester.pumpWidget(buildPage());
      await tester.pumpAndSettle();

      // Activate multi-select.
      final checkboxes = find.byType(Checkbox);
      await tester.tap(checkboxes.first);
      await tester.pumpAndSettle();

      // Tap the Publish button.
      await tester.tap(find.text('Publish'));
      await tester.pumpAndSettle();

      // Cancel the dialog.
      await tester.tap(find.text('Cancel'));
      await tester.pumpAndSettle();

      // Multi-select should still be active (nothing changed).
      expect(find.text('1 selected'), findsOneWidget);
    });

    testWidgets('plural product count in confirmation dialog', (tester) async {
      tester.view.physicalSize = const Size(600, 800);
      tester.view.devicePixelRatio = 1.0;
      addTearDown(tester.view.resetPhysicalSize);
      addTearDown(tester.view.resetDevicePixelRatio);

      await tester.pumpWidget(buildPage());
      await tester.pumpAndSettle();

      // Select two products.
      final checkboxes = find.byType(Checkbox);
      await tester.tap(checkboxes.at(0));
      await tester.pumpAndSettle();
      await tester.tap(checkboxes.at(1));
      await tester.pumpAndSettle();

      expect(find.text('2 selected'), findsOneWidget);

      // Tap the Publish button.
      await tester.tap(find.text('Publish'));
      await tester.pumpAndSettle();

      // Dialog should use plural form.
      expect(find.text('Publish 2 products to the store?'), findsOneWidget);

      // Dismiss.
      await tester.tap(find.text('Cancel'));
      await tester.pumpAndSettle();
    });
  });
}
