import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:recipe_flutter/core/ui/app_shell.dart';
import 'package:recipe_flutter/features/admin/data/admin_repository.dart';
import 'package:recipe_flutter/features/admin/domain/admin_ai_trace.dart';
import 'package:recipe_flutter/features/admin/domain/admin_ai_trace_detail.dart';
import 'package:recipe_flutter/features/admin/presentation/admin_ai_panel.dart';
import 'package:recipe_flutter/features/admin/presentation/admin_screen.dart';
import 'package:recipe_flutter/features/auth/data/auth_providers.dart';

class _FakeAdminRepository implements AdminRepository {
  final AdminAiTraceListResponse flyerList;
  final AdminAiTraceListResponse receiptList;
  final Map<String, AdminAiTraceDetail> details;

  _FakeAdminRepository({
    required this.flyerList,
    required this.receiptList,
    required this.details,
  });

  @override
  Future<AdminAiTraceListResponse> listAiTraces({
    required AdminAiTraceSource source,
    int limit = 25,
    String? cursor,
    String? period,
    bool onlyErrors = false,
  }) async {
    return source == AdminAiTraceSource.flyer ? flyerList : receiptList;
  }

  @override
  Future<AdminAiTraceDetail> getAiTraceById(String traceId) async {
    return details[traceId] ?? details.values.first;
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

Widget _buildPanelApp(AdminRepository repo) {
  return ProviderScope(
    overrides: [
      adminRepositoryProvider.overrideWithValue(repo),
    ],
    child: const MaterialApp(
      home: Scaffold(
        body: AdminAiPanel(embedded: true),
      ),
    ),
  );
}

void main() {
  final veryLargeOutput = '{"payload":"${List.filled(13050, 'x').join()}"}';

  final flyerItem = AdminAiTraceListItem(
    id: 'flyer-101',
    source: AdminAiTraceSource.flyer,
    status: AdminAiTraceStatus.warning,
    createdAt: DateTime.parse('2026-05-20T12:34:56.000Z'),
    userId: 7,
    userLabel: 'admin',
    sessionId: 101,
    fileName: 'willys-v20.pdf',
    model: 'ministral-8b-2512',
    durationMs: 1880,
    warningsCount: 2,
    hasPrompt: true,
    hasOutput: true,
    error: 'Det finns 2 varningar i detaljvyn.',
  );

  final flyerDetail = AdminAiTraceDetail(
    id: 'flyer-101',
    source: AdminAiTraceSource.flyer,
    status: AdminAiTraceStatus.warning,
    createdAt: DateTime.parse('2026-05-20T12:34:56.000Z'),
    userId: 7,
    userLabel: 'admin',
    sessionId: 101,
    fileName: 'willys-v20.pdf',
    model: 'ministral-8b-2512',
    durationMs: 1880,
    retryCount: 1,
    chunkCount: 3,
    warnings: const ['parse:low_confidence', 'match:no_match'],
    error: null,
    prompt: 'Prompttext exempel',
    rawOutput: veryLargeOutput,
    normalizedOutput: null,
    summary: const {'itemCount': 1},
  );

  group('Admin AI tab and panel', () {
    testWidgets('Admin main route query tab=ai renders AI panel',
        (tester) async {
      final fakeRepo = _FakeAdminRepository(
        flyerList:
            AdminAiTraceListResponse(items: [flyerItem], nextCursor: null),
        receiptList:
            const AdminAiTraceListResponse(items: [], nextCursor: null),
        details: {'flyer-101': flyerDetail},
      );

      await tester.pumpWidget(
        ProviderScope(
          overrides: [
            adminRepositoryProvider.overrideWithValue(fakeRepo),
          ],
          child: const MaterialApp(
            home: Scaffold(
              body: AdminScreen(initialTab: AdminViewTab.ai),
            ),
          ),
        ),
      );
      await tester.pumpAndSettle();

      expect(find.text('Kvitto'), findsOneWidget);
      expect(find.text('Flyer'), findsOneWidget);
      expect(find.text('willys-v20.pdf'), findsOneWidget);
    });

    testWidgets('AppShell shows AI top chip and navigates with query',
        (tester) async {
      String? navigatedTo;

      await tester.pumpWidget(
        ProviderScope(
          overrides: [
            isAdminProvider.overrideWithValue(true),
          ],
          child: MaterialApp(
            home: AppShell(
              location: '/admin?tab=ai',
              onNavigateToPath: (path) => navigatedTo = path,
              child: const SizedBox.shrink(),
            ),
          ),
        ),
      );

      await tester.pumpAndSettle();

      expect(find.text('AI'), findsOneWidget);
      await tester.tap(find.text('Databas'));
      await tester.pump();

      expect(navigatedTo, '/admin?tab=database');
    });

    testWidgets('Source switching toggles between Flyer and Kvitto views',
        (tester) async {
      final fakeRepo = _FakeAdminRepository(
        flyerList:
            AdminAiTraceListResponse(items: [flyerItem], nextCursor: null),
        receiptList:
            const AdminAiTraceListResponse(items: [], nextCursor: null),
        details: {'flyer-101': flyerDetail},
      );

      await tester.pumpWidget(_buildPanelApp(fakeRepo));
      await tester.pumpAndSettle();

      expect(find.text('willys-v20.pdf'), findsOneWidget);

      await tester.tap(find.text('Kvitto'));
      await tester.pumpAndSettle();
      expect(find.text('Receipt trace-data saknas i recipe-api i denna fas.'),
          findsOneWidget);

      await tester.tap(find.text('Flyer'));
      await tester.pumpAndSettle();
      expect(find.text('willys-v20.pdf'), findsOneWidget);
    });

    testWidgets('Prompt/output are selectable and warning details are visible',
        (tester) async {
      await tester.binding.setSurfaceSize(const Size(1400, 1200));
      final fakeRepo = _FakeAdminRepository(
        flyerList:
            AdminAiTraceListResponse(items: [flyerItem], nextCursor: null),
        receiptList:
            const AdminAiTraceListResponse(items: [], nextCursor: null),
        details: {'flyer-101': flyerDetail},
      );

      await tester.pumpWidget(_buildPanelApp(fakeRepo));
      await tester.pumpAndSettle();
      await tester.pump(const Duration(milliseconds: 500));

      await tester.tap(find.byType(ListTile).first);
      await tester.pumpAndSettle();
      await tester.pump(const Duration(milliseconds: 500));

      expect(find.text('Sammanfattning'), findsOneWidget);
      expect(find.text('Varningar (2)'), findsOneWidget);
      expect(find.text('parse:low_confidence'), findsOneWidget);
      expect(find.text('match:no_match'), findsOneWidget);
      final detailScroll = find.byType(Scrollable).last;
      await tester.scrollUntilVisible(
        find.text('Model Output'),
        200,
        scrollable: detailScroll,
      );
      await tester.pumpAndSettle();

      expect(find.text('Model Output'), findsOneWidget);
      expect(find.byType(SelectableText), findsWidgets);
      expect(find.text('Visa hela outputen'), findsOneWidget);

      await tester.tap(find.text('Visa hela outputen'));
      await tester.pumpAndSettle();
      expect(find.text('Visa mindre'), findsOneWidget);

      final copyPrompt = find.byTooltip('Kopiera');
      final copyOutput = find.byTooltip('Kopiera JSON');
      final copyWarnings = find.byTooltip('Kopiera alla varningar');
      expect(copyPrompt, findsOneWidget);
      expect(copyOutput, findsOneWidget);
      expect(copyWarnings, findsOneWidget);

      await tester.tap(copyPrompt);
      await tester.pumpAndSettle();
      expect(tester.takeException(), isNull);

      await tester.tap(copyOutput);
      await tester.pumpAndSettle();
      expect(tester.takeException(), isNull);

      await tester.tap(copyWarnings);
      await tester.pumpAndSettle();
      expect(tester.takeException(), isNull);

      addTearDown(() => tester.binding.setSurfaceSize(null));
    });
  });
}
