import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:iop_client/control_plane_status_client.dart';
import 'package:iop_client/main.dart';
import 'package:iop_client/widgets/nodes_panel.dart';
import 'support/client_test_harness.dart';

void main() {
  // [REVIEW_API-1] Regression: health=degraded, status=active -> yellow state text/color
  testWidgets(
    'Provider with health=degraded and status=active shows DEGRADED text with yellow color',
    (WidgetTester tester) async {
      final fakeClient = FakeClientWireClient(shouldSuccess: true);
      final fakeStatusRepo = FakeControlPlaneStatusRepository();

      // Override the OpenAI provider to have health=degraded, status=active
      // This is already set in the fake repo, but verify via the widget
      await tester.pumpWidget(
        IopClientApp(testClient: fakeClient, statusRepository: fakeStatusRepo),
      );
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 100));

      await tester.tap(find.byTooltip('Nodes'));
      await tester.pumpAndSettle();

      // Scroll to reveal node-2's provider catalog
      await tester.drag(find.byType(ListView), const Offset(0.0, -1500.0));
      await tester.pumpAndSettle();

      // The degraded provider should show DEGRADED text (not ACTIVE)
      expect(find.textContaining('DEGRADED'), findsOneWidget);
      // Also confirm the provider id is shown
      expect(find.text('provider-openai'), findsOneWidget);
    },
  );

  // [REVIEW_API-2] DTO JSON parsing test
  testWidgets(
    'EdgeStatusResponseView.fromJson parses raw JSON and validates provider_snapshots',
    (WidgetTester tester) async {
      // This test verifies the HTTP JSON DTO parsing path used by
      // HttpControlPlaneStatusRepository.fetchEdgeStatus.
      final rawJson = {
        'request_id': 'test-req-001',
        'edge_id': 'edge-test',
        'edge_name': 'Edge Test Node',
        'observed_time_unix_nano': 1716584400000000000,
        'nodes': [
          {
            'node_id': 'node-1',
            'alias': 'Test Node',
            'label': 'GPU-A100',
            'connected': true,
            'config': {
              'adapters': [
                {'type': 'ollama', 'enabled': true},
              ],
              'concurrency': 8,
            },
            'provider_snapshots': [
              {
                'id': 'provider-ollama',
                'adapter': 'ollama',
                'type': 'llm',
                'category': 'inference',
                'status': 'active',
                'health': 'degraded',
                'capacity': 10,
                'in_flight': 3,
                'queued': 1,
                'load_ratio': 0.3,
                'served_models': ['llama-3.1', 'mistral'],
                'lifecycle_capabilities': ['start', 'stop', 'restart'],
              },
              {
                'id': 'provider-vllm',
                'adapter': 'vllm',
                'type': 'llm',
                'category': 'inference',
                'status': 'ready',
                'health': 'healthy',
                'capacity': 20,
                'in_flight': 0,
                'queued': 0,
                'load_ratio': 0.0,
                'served_models': ['vicuna'],
                'lifecycle_capabilities': ['start', 'stop'],
              },
            ],
          },
        ],
        'capabilities': [
          {
            'kind': 'Serving',
            'available': true,
            'status': 'ready',
            'summary': 'Active',
          },
        ],
        'metadata': {'region': 'us-west'},
        'error': '',
      };

      // Parse the raw JSON using the DTO from
      // apps/client/lib/control_plane_status_dto.dart
      final parsed = EdgeStatusResponseView.fromJson(rawJson);

      // Validate top-level fields
      expect(parsed.requestId, equals('test-req-001'));
      expect(parsed.edgeId, equals('edge-test'));
      expect(parsed.edgeName, equals('Edge Test Node'));
      expect(parsed.observedTimeUnixNano, equals(1716584400000000000));
      expect(parsed.nodes.length, equals(1));
      expect(parsed.error, equals(''));

      // Validate node fields
      final node = parsed.nodes.first;
      expect(node.nodeId, equals('node-1'));
      expect(node.alias, equals('Test Node'));
      expect(node.label, equals('GPU-A100'));
      expect(node.connected, isTrue);
      expect(node.config, isNotNull);
      expect(node.config!.adapters.length, equals(1));
      expect(node.config!.adapters.first.type, equals('ollama'));
      expect(node.config!.adapters.first.enabled, isTrue);
      expect(node.config!.concurrency, equals(8));

      // Validate provider_snapshots fields
      final prov0 = node.providerSnapshots[0];
      expect(prov0.id, equals('provider-ollama'));
      expect(prov0.adapter, equals('ollama'));
      expect(prov0.type, equals('llm'));
      expect(prov0.category, equals('inference'));
      expect(prov0.status, equals('active'));
      expect(prov0.health, equals('degraded'));
      expect(prov0.capacity, equals(10));
      expect(prov0.inFlight, equals(3));
      expect(prov0.queued, equals(1));
      expect(prov0.loadRatio, equals(0.3));
      expect(prov0.servedModels, equals(['llama-3.1', 'mistral']));
      expect(prov0.lifecycleCapabilities, equals(['start', 'stop', 'restart']));

      // Validate second provider snapshot
      final prov1 = node.providerSnapshots[1];
      expect(prov1.id, equals('provider-vllm'));
      expect(prov1.adapter, equals('vllm'));
      expect(prov1.status, equals('ready'));
      expect(prov1.health, equals('healthy'));
      expect(prov1.capacity, equals(20));
      expect(prov1.inFlight, equals(0));
      expect(prov1.queued, equals(0));
      expect(prov1.loadRatio, equals(0.0));
      expect(prov1.servedModels, equals(['vicuna']));
      expect(prov1.lifecycleCapabilities, equals(['start', 'stop']));

      // Validate capabilities and metadata
      expect(parsed.capabilities.length, equals(1));
      expect(parsed.capabilities.first.kind, equals('Serving'));
      expect(parsed.capabilities.first.available, isTrue);
      expect(parsed.metadata, equals({'region': 'us-west'}));

      // Verify that the same raw JSON can also be rendered in the widget.
      // This connects the DTO parsing path to the UI path.
      final statusView = EdgeStatusResponseView.fromJson(rawJson);
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: NodesPanel(
              edges: [
                FleetEdgeView(
                  edgeId: 'edge-test',
                  edgeName: 'Edge Test Node',
                  version: '1.0.0',
                  protocol: 'iop-wire-v1',
                  connected: true,
                  health: 'healthy',
                  lastSeen: DateTime.now(),
                  nodeCount: 1,
                  capabilities: [],
                  error: '',
                ),
              ],
              selectedEdgeId: 'edge-test',
              selectedEdgeStatus: statusView,
              isLoading: false,
              error: null,
              onSelectEdge: (_) {},
              onRefresh: () {},
            ),
          ),
        ),
      );
      await tester.pump();

      // Verify degraded provider shows correctly via _stateColor semantics
      expect(find.textContaining('DEGRADED'), findsOneWidget);
      expect(find.textContaining('HEALTHY'), findsOneWidget);
      expect(find.textContaining('provider-ollama'), findsOneWidget);
      expect(find.textContaining('provider-vllm'), findsOneWidget);
    },
  );

  // [G03] Control Plane predecessor values: health=available/status=available
  testWidgets(
    'Provider with health=available and status=available shows AVAILABLE text with green color',
    (WidgetTester tester) async {
      // Test uses standalone NodesPanel with available providers.
      // The DTO test below covers JSON parsing for all predecessor values.
      final statusView = EdgeStatusResponseView.fromJson({
        'request_id': 'test-req-g03-solo',
        'edge_id': 'edge-g03',
        'edge_name': 'Edge G03 Test',
        'observed_time_unix_nano': 1716584400000000000,
        'nodes': [
          {
            'node_id': 'node-g03',
            'alias': 'G03 Test Node',
            'label': 'GPU-Test',
            'connected': true,
            'config': {
              'adapters': [
                {'type': 'ollama', 'enabled': true},
              ],
              'concurrency': 4,
            },
            'provider_snapshots': [
              {
                'id': 'provider-available',
                'adapter': 'ollama',
                'type': 'llm',
                'category': 'inference',
                'status': 'available',
                'health': 'available',
                'capacity': 10,
                'in_flight': 2,
                'queued': 0,
                'load_ratio': 0.2,
                'served_models': ['llama-3.1'],
                'lifecycle_capabilities': ['start', 'stop'],
              },
            ],
          },
        ],
        'capabilities': [],
        'metadata': {},
        'error': '',
      });

      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: NodesPanel(
              edges: [
                FleetEdgeView(
                  edgeId: 'edge-g03',
                  edgeName: 'Edge G03 Test',
                  version: '1.0.0',
                  protocol: 'iop-wire-v1',
                  connected: true,
                  health: 'healthy',
                  lastSeen: DateTime.now(),
                  nodeCount: 1,
                  capabilities: [],
                  error: '',
                ),
              ],
              selectedEdgeId: 'edge-g03',
              selectedEdgeStatus: statusView,
              isLoading: false,
              error: null,
              onSelectEdge: (_) {},
              onRefresh: () {},
            ),
          ),
        ),
      );
      await tester.pump();

      // health=available/status=available should show AVAILABLE text in green (#10B981)
      expect(find.text('AVAILABLE'), findsOneWidget);
      expect(find.text('provider-available'), findsOneWidget);

      // [G02] Status label color assertions
      // Find the AVAILABLE status label Text widget (inside Container) and verify its color
      final availableLabelFinder = find.byWidgetPredicate((Widget widget) {
        if (widget is Text) {
          return widget.data == 'AVAILABLE' && widget.style != null;
        }
        return false;
      });
      expect(availableLabelFinder, findsOneWidget);
      final availableLabel =
          availableLabelFinder.evaluate().first.widget as Text;
      expect(availableLabel.style?.color, equals(const Color(0xFF10B981)));
    },
  );

  // [G03] DTO JSON parsing test for Control Plane predecessor values
  testWidgets(
    'EdgeStatusResponseView parses health=available/status=available and health=unavailable/status=backlog',
    (WidgetTester tester) async {
      final rawJson = {
        'request_id': 'test-req-g03',
        'edge_id': 'edge-g03',
        'edge_name': 'Edge G03 Test',
        'observed_time_unix_nano': 1716584400000000000,
        'nodes': [
          {
            'node_id': 'node-g03',
            'alias': 'G03 Test Node',
            'label': 'GPU-Test',
            'connected': true,
            'config': {
              'adapters': [
                {'type': 'ollama', 'enabled': true},
              ],
              'concurrency': 4,
            },
            'provider_snapshots': [
              {
                // health=available, status=available -> green
                'id': 'provider-available',
                'adapter': 'ollama',
                'type': 'llm',
                'category': 'inference',
                'status': 'available',
                'health': 'available',
                'capacity': 10,
                'in_flight': 2,
                'queued': 0,
                'load_ratio': 0.2,
                'served_models': ['llama-3.1'],
                'lifecycle_capabilities': ['start', 'stop'],
              },
              {
                // health=unavailable, status=backlog -> red
                'id': 'provider-unavailable',
                'adapter': 'vllm',
                'type': 'llm',
                'category': 'inference',
                'status': 'backlog',
                'health': 'unavailable',
                'capacity': 20,
                'in_flight': 0,
                'queued': 0,
                'load_ratio': 0.0,
                'served_models': [],
                'lifecycle_capabilities': ['start', 'stop'],
              },
              {
                // health=unknown, status=unknown -> neutral grey
                'id': 'provider-unknown',
                'adapter': 'openai',
                'type': 'llm',
                'category': 'external',
                'status': 'unknown',
                'health': '',
                'capacity': 100,
                'in_flight': 0,
                'queued': 0,
                'load_ratio': 0.0,
                'served_models': ['gpt-4'],
                'lifecycle_capabilities': [],
              },
            ],
          },
        ],
        'capabilities': [],
        'metadata': {},
        'error': '',
      };

      // Parse the raw JSON
      final parsed = EdgeStatusResponseView.fromJson(rawJson);
      expect(parsed.requestId, equals('test-req-g03'));
      expect(parsed.edgeId, equals('edge-g03'));
      expect(parsed.nodes.length, equals(1));

      // Validate provider snapshots
      final prov0 = parsed.nodes[0].providerSnapshots[0];
      expect(prov0.id, equals('provider-available'));
      expect(prov0.health, equals('available'));
      expect(prov0.status, equals('available'));

      final prov1 = parsed.nodes[0].providerSnapshots[1];
      expect(prov1.id, equals('provider-unavailable'));
      expect(prov1.health, equals('unavailable'));
      expect(prov1.status, equals('backlog'));

      final prov2 = parsed.nodes[0].providerSnapshots[2];
      expect(prov2.id, equals('provider-unknown'));
      expect(prov2.health, equals(''));
      expect(prov2.status, equals('unknown'));

      // Verify that the same raw JSON can be rendered in the widget.
      final statusView = EdgeStatusResponseView.fromJson(rawJson);
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: NodesPanel(
              edges: [
                FleetEdgeView(
                  edgeId: 'edge-g03',
                  edgeName: 'Edge G03 Test',
                  version: '1.0.0',
                  protocol: 'iop-wire-v1',
                  connected: true,
                  health: 'healthy',
                  lastSeen: DateTime.now(),
                  nodeCount: 1,
                  capabilities: [],
                  error: '',
                ),
              ],
              selectedEdgeId: 'edge-g03',
              selectedEdgeStatus: statusView,
              isLoading: false,
              error: null,
              onSelectEdge: (_) {},
              onRefresh: () {},
            ),
          ),
        ),
      );
      await tester.pump();

      // Verify available provider shows AVAILABLE text
      expect(find.text('AVAILABLE'), findsWidgets);
      expect(find.textContaining('provider-available'), findsOneWidget);

      // [G02] UNAVAILABLE status label color assertion (#EF4444 red)
      final unavailableLabelFinder = find.byWidgetPredicate((Widget widget) {
        if (widget is Text) {
          return widget.data == 'UNAVAILABLE' && widget.style != null;
        }
        return false;
      });
      expect(unavailableLabelFinder, findsOneWidget);
      final unavailableLabel =
          unavailableLabelFinder.evaluate().first.widget as Text;
      expect(unavailableLabel.style?.color, equals(const Color(0xFFEF4444)));

      // [G02] UNKNOWN status label color assertion (#64748B grey)
      // For provider-unknown, health='' so status='unknown' -> _stateColor returns Color(0xFF64748B)
      // displayState = p.health.isNotEmpty ? p.health : p.status = 'unknown'
      // displayState.toUpperCase() = 'UNKNOWN'
      final unknownLabelFinder = find.byWidgetPredicate((Widget widget) {
        if (widget is Text) {
          return widget.data == 'UNKNOWN' && widget.style != null;
        }
        return false;
      });
      expect(unknownLabelFinder, findsOneWidget);
      final unknownLabel = unknownLabelFinder.evaluate().first.widget as Text;
      expect(unknownLabel.style?.color, equals(const Color(0xFF64748B)));

      // Verify unavailable provider shows UNAVAILABLE text
      expect(find.text('UNAVAILABLE'), findsWidgets);
      expect(find.textContaining('provider-unavailable'), findsOneWidget);

      // Verify unknown provider shows UNKNOWN text (from status)
      expect(find.text('UNKNOWN'), findsWidgets);
      expect(find.textContaining('provider-unknown'), findsOneWidget);
    },
  );
}
