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

// ── Fake repository ───────────────────────────────────────────────────────────

class _FakeRepo implements ProductPublishingRepository {
  final List<ProductCategory> _categories;
  bool createCategoryCalled = false;
  bool deleteCategoryCalled = false;
  int? lastDeletedId;
  String? lastCreatedName;
  Object? getCategoriesToThrow;
  Object? createCategoryToThrow;
  Object? deleteCategoryToThrow;

  _FakeRepo({List<ProductCategory>? categories})
    : _categories =
          categories ??
          [
            const ProductCategory(
              id: 1,
              name: 'Bowl Cozies',
              slug: 'bowl-cozies',
              parentId: 0,
              count: 3,
            ),
            const ProductCategory(id: 2, name: 'Coasters', slug: 'coasters', parentId: 0, count: 1),
          ];

  @override
  Future<List<ProductCategory>> getCategories() async {
    if (getCategoriesToThrow != null) throw getCategoriesToThrow!;
    return List.of(_categories);
  }

  @override
  Future<ProductCategory> createCategory({required String name, int parentId = 0}) async {
    if (createCategoryToThrow != null) throw createCategoryToThrow!;
    createCategoryCalled = true;
    lastCreatedName = name;
    final newCat = ProductCategory(
      id: 99,
      name: name,
      slug: name.toLowerCase().replaceAll(' ', '-'),
      parentId: parentId,
      count: 0,
    );
    _categories.add(newCat);
    return newCat;
  }

  @override
  Future<void> deleteCategory(int categoryId, {bool force = true}) async {
    if (deleteCategoryToThrow != null) throw deleteCategoryToThrow!;
    deleteCategoryCalled = true;
    lastDeletedId = categoryId;
    _categories.removeWhere((c) => c.id == categoryId);
  }

  // ── Unused stubs ──────────────────────────────────────────────────────────

  @override
  Future<List<ProductDraft>> getProductDrafts() async => [];

  @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();

  @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<ProductCategory> updateCategory(int categoryId, {String? name, int? parentId}) async =>
      throw UnimplementedError();

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

// ── Helpers ───────────────────────────────────────────────────────────────────

Widget _buildPage(_FakeRepo repo) => MaterialApp(home: CategoryManagementPage(repository: repo));

// ── Tests ─────────────────────────────────────────────────────────────────────

void main() {
  group('CategoryManagementPage', () {
    testWidgets('shows loading indicator while fetching', (tester) async {
      // Use a repo that never completes to keep the loading state visible.
      final repo = _FakeRepo();
      // Intercept before pump settles.
      await tester.pumpWidget(_buildPage(repo));
      // First frame: loading.
      expect(find.byType(CircularProgressIndicator), findsOneWidget);
    });

    testWidgets('shows category list after load', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      expect(find.text('Bowl Cozies'), findsOneWidget);
      expect(find.text('Coasters'), findsOneWidget);
    });

    testWidgets('shows product count in subtitle', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      // Bowl Cozies has count=3, Coasters has count=1.
      expect(find.textContaining('3 products'), findsOneWidget);
      expect(find.textContaining('1 product'), findsOneWidget);
    });

    testWidgets('shows empty state when no categories', (tester) async {
      final repo = _FakeRepo(categories: []);
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      expect(find.text('No categories yet.'), findsOneWidget);
      expect(find.text('Create First Category'), findsOneWidget);
    });

    testWidgets('shows error state when load fails', (tester) async {
      final repo = _FakeRepo()..getCategoriesToThrow = Exception('network error');
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      expect(find.text('Failed to load categories.'), findsOneWidget);
      expect(find.text('Retry'), findsOneWidget);
    });

    testWidgets('retry button reloads categories', (tester) async {
      final repo = _FakeRepo()..getCategoriesToThrow = Exception('network error');
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      // Fix the error and retry.
      repo.getCategoriesToThrow = null;
      await tester.tap(find.text('Retry'));
      await tester.pumpAndSettle();

      expect(find.text('Bowl Cozies'), findsOneWidget);
      expect(find.text('Failed to load categories.'), findsNothing);
    });

    testWidgets('New Category FAB is visible', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      expect(find.text('New Category'), findsOneWidget);
    });

    testWidgets('tapping New Category FAB opens create dialog', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      await tester.tap(find.text('New Category'));
      await tester.pumpAndSettle();

      expect(find.text('New Category'), findsWidgets); // dialog title + FAB
      expect(find.text('Category Name *'), findsOneWidget);
    });

    testWidgets('create dialog Cancel does not call createCategory', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      await tester.tap(find.text('New Category'));
      await tester.pumpAndSettle();

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

      expect(repo.createCategoryCalled, isFalse);
    });

    testWidgets('create dialog shows error when name is empty', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      await tester.tap(find.text('New Category'));
      await tester.pumpAndSettle();

      // Tap Create without entering a name.
      await tester.tap(find.text('Create'));
      await tester.pumpAndSettle();

      expect(find.text('Category name is required.'), findsOneWidget);
      expect(repo.createCategoryCalled, isFalse);
    });

    testWidgets('creating a category calls repository and reloads list', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      await tester.tap(find.text('New Category'));
      await tester.pumpAndSettle();

      await tester.enterText(find.widgetWithText(TextField, 'Category Name *'), 'Pot Holders');
      await tester.tap(find.text('Create'));
      await tester.pumpAndSettle();

      expect(repo.createCategoryCalled, isTrue);
      expect(repo.lastCreatedName, 'Pot Holders');
      // New category should appear in the list.
      expect(find.text('Pot Holders'), findsOneWidget);
    });

    testWidgets('delete icon is shown for each category', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      // Two categories → two delete icons.
      expect(find.byIcon(Icons.delete_outline), findsNWidgets(2));
    });

    testWidgets('tapping delete icon opens confirmation dialog', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      await tester.tap(find.byIcon(Icons.delete_outline).first);
      await tester.pumpAndSettle();

      expect(find.text('Delete Category'), findsOneWidget);
      expect(find.text('Delete'), findsOneWidget);
    });

    testWidgets('cancelling delete dialog does not call deleteCategory', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      await tester.tap(find.byIcon(Icons.delete_outline).first);
      await tester.pumpAndSettle();

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

      expect(repo.deleteCategoryCalled, isFalse);
    });

    testWidgets('confirming delete calls repository and removes category', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      // Delete the first category (Bowl Cozies, id=1).
      await tester.tap(find.byIcon(Icons.delete_outline).first);
      await tester.pumpAndSettle();

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

      expect(repo.deleteCategoryCalled, isTrue);
      expect(repo.lastDeletedId, 1);
      expect(find.text('Bowl Cozies'), findsNothing);
    });

    testWidgets('refresh button reloads categories', (tester) async {
      final repo = _FakeRepo();
      await tester.pumpWidget(_buildPage(repo));
      await tester.pumpAndSettle();

      // Add a category directly to the repo (simulating external change).
      repo._categories.add(
        const ProductCategory(id: 10, name: 'New Cat', slug: 'new-cat', parentId: 0, count: 0),
      );

      await tester.tap(find.byIcon(Icons.refresh));
      await tester.pumpAndSettle();

      expect(find.text('New Cat'), findsOneWidget);
    });
  });
}
