import 'dart:convert';
import 'dart:io';

import 'package:flutter_mcp_toolkit_server/flutter_mcp_core.dart';
import 'package:flutter_mcp_toolkit_server/src/capabilities/visual_capture/desktop_window_screenshot.dart';
import 'package:test/test.dart';

void main() {
  group('inferMacOsAppCandidates', () {
    test('reads bundle and AppInfo candidates', () async {
      final tempDir = await Directory.systemTemp.createTemp(
        'mcp_window_capture',
      );
      addTearDown(() async {
        if (tempDir.existsSync()) {
          await tempDir.delete(recursive: true);
        }
      });

      final bundleDir = Directory(
        '${tempDir.path}/build/macos/Build/Products/Debug/sample_app.app/Contents/MacOS',
      )..createSync(recursive: true);
      File('${bundleDir.path}/sample_app').writeAsStringSync('');
      File('${tempDir.path}/macos/Runner/Configs/AppInfo.xcconfig')
        ..createSync(recursive: true)
        ..writeAsStringSync('PRODUCT_NAME = sample_app\n');

      final candidates = inferMacOsAppCandidates(projectDir: tempDir.path);
      expect(candidates, contains('sample_app'));
      expect(candidates.length, equals(candidates.toSet().length));
    });
  });

  group('MacOsDesktopWindowScreenshotService', () {
    test('returns null for non-macos devices', () async {
      final service = MacOsDesktopWindowScreenshotService();
      final capture = await service.capture(
        projectDir: Directory.systemTemp.path,
        device: 'web',
        compress: true,
      );
      expect(capture, isNull);
    });

    test('captures base64 PNG payload from swift helper output', () async {
      final tempDir = await Directory.systemTemp.createTemp(
        'mcp_window_capture',
      );
      addTearDown(() async {
        if (tempDir.existsSync()) {
          await tempDir.delete(recursive: true);
        }
      });

      final bundleDir = Directory(
        '${tempDir.path}/build/macos/Build/Products/Debug/sample_app.app/Contents/MacOS',
      )..createSync(recursive: true);
      File('${bundleDir.path}/sample_app').writeAsStringSync('');

      String? compiledBinary;

      final service = MacOsDesktopWindowScreenshotService(
        runProcess: (final executable, final arguments) async {
          if (executable == 'swiftc') {
            compiledBinary = arguments.last;
            return ProcessResult(1, 0, '', '');
          }
          expect(executable, equals(compiledBinary));
          expect(arguments.first, equals('capture'));
          expect(arguments[1], equals('--pid'));
          expect(arguments[2], equals('98223'));
          final payload = <String, Object?>{
            'ok': true,
            'appName': 'sample_app',
            'windowOwnerPid': 98223,
            'windowId': 77,
            'windowTitle': 'Sample Window',
            'windowSelectionSource': 'all_windows_fallback',
            'windowCaptureVisibility': 'offscreen_or_hidden',
            'windowBounds': <String, Object?>{
              'x': 10.0,
              'y': 20.0,
              'width': 300.0,
              'height': 200.0,
            },
            'pngBase64': base64Encode(<int>[1, 2, 3, 4]),
            'permissionStatus': 'granted',
          };
          return ProcessResult(1, 0, jsonEncode(payload), '');
        },
      );

      final capture = await service.capture(
        projectDir: tempDir.path,
        device: 'macos',
        compress: true,
        targetPid: 98223,
        cacheDir: tempDir.path,
      );

      expect(capture, isNotNull);
      expect(capture!.captureMode, equals('desktop_window'));
      expect(capture.images, hasLength(1));
      expect(capture.metadata['appName'], equals('sample_app'));
      expect(capture.metadata['windowOwnerPid'], equals(98223));
      expect(capture.metadata['windowId'], equals(77));
      expect(capture.metadata['windowTitle'], equals('Sample Window'));
      expect(
        capture.metadata['windowSelectionSource'],
        equals('all_windows_fallback'),
      );
      expect(
        capture.metadata['windowCaptureVisibility'],
        equals('offscreen_or_hidden'),
      );
      expect(compiledBinary, isNotNull);
    });

    test(
      'compiled helper source exits explicitly after emitting payload',
      () async {
        final tempDir = await Directory.systemTemp.createTemp(
          'mcp_window_capture',
        );
        addTearDown(() async {
          if (tempDir.existsSync()) {
            await tempDir.delete(recursive: true);
          }
        });

        final bundleDir = Directory(
          '${tempDir.path}/build/macos/Build/Products/Debug/sample_app.app/Contents/MacOS',
        )..createSync(recursive: true);
        File('${bundleDir.path}/sample_app').writeAsStringSync('');

        late final String helperSourcePath;
        final service = MacOsDesktopWindowScreenshotService(
          runProcess: (final executable, final arguments) async {
            if (executable == 'swiftc') {
              helperSourcePath = arguments[1];
              return ProcessResult(1, 0, '', '');
            }
            final payload = <String, Object?>{
              'ok': true,
              'appName': 'sample_app',
              'windowOwnerPid': 98223,
              'windowId': 77,
              'windowTitle': 'Sample Window',
              'windowSelectionSource': 'on_screen',
              'windowCaptureVisibility': 'on_screen',
              'windowBounds': <String, Object?>{
                'x': 10.0,
                'y': 20.0,
                'width': 300.0,
                'height': 200.0,
              },
              'pngBase64': base64Encode(<int>[1, 2, 3, 4]),
              'permissionStatus': 'granted',
            };
            return ProcessResult(1, 0, jsonEncode(payload), '');
          },
        );

        await service.capture(
          projectDir: tempDir.path,
          device: 'macos',
          compress: true,
          targetPid: 98223,
          cacheDir: tempDir.path,
        );

        final helperSource = File(helperSourcePath).readAsStringSync();
        expect(helperSource, contains('FileHandle.standardOutput.write(data)'));
        expect(helperSource, contains('Foundation.exit(0)'));
      },
    );

    test('surfaces structured helper failures with details', () async {
      final tempDir = await Directory.systemTemp.createTemp(
        'mcp_window_capture',
      );
      addTearDown(() async {
        if (tempDir.existsSync()) {
          await tempDir.delete(recursive: true);
        }
      });

      final bundleDir = Directory(
        '${tempDir.path}/build/macos/Build/Products/Debug/sample_app.app/Contents/MacOS',
      )..createSync(recursive: true);
      File('${bundleDir.path}/sample_app').writeAsStringSync('');

      String? compiledBinary;
      final service = MacOsDesktopWindowScreenshotService(
        runProcess: (final executable, final arguments) async {
          if (executable == 'swiftc') {
            compiledBinary = arguments.last;
            return ProcessResult(1, 0, '', '');
          }
          expect(executable, equals(compiledBinary));
          final payload = <String, Object?>{
            'ok': false,
            'error': 'window_not_found',
            'details': <String, Object?>{
              'visibleOwners': <String>['Codex'],
              'allOwners': <String>['Codex', 'sample_app'],
            },
          };
          return ProcessResult(1, 0, jsonEncode(payload), '');
        },
      );

      expect(
        () => service.capture(
          projectDir: tempDir.path,
          device: 'macos',
          compress: true,
          targetPid: 98223,
          cacheDir: tempDir.path,
        ),
        throwsA(
          isA<DesktopWindowCaptureException>()
              .having(
                (final e) => e.message,
                'message',
                contains('window_not_found'),
              )
              .having(
                (final e) => e.details['allOwners'],
                'details.allOwners',
                equals(const <String>['Codex', 'sample_app']),
              ),
        ),
      );
    });

    test('status/request/open-settings parse helper payloads', () async {
      final calls = <String>[];
      String? compiledBinary;
      final service = MacOsDesktopWindowScreenshotService(
        runProcess: (final executable, final arguments) async {
          if (executable == 'swiftc') {
            compiledBinary = arguments.last;
            return ProcessResult(1, 0, '', '');
          }
          expect(executable, equals(compiledBinary));
          calls.add(arguments.first);
          final payload = switch (arguments.first) {
            'status' => <String, Object?>{
              'ok': true,
              'status': 'not_determined',
              'message': 'status',
              'canRequest': true,
              'canOpenSettings': true,
              'details': <String, Object?>{},
            },
            'request' => <String, Object?>{
              'ok': true,
              'status': 'granted',
              'message': 'request',
              'canRequest': true,
              'canOpenSettings': true,
              'details': <String, Object?>{},
            },
            'open-settings' => <String, Object?>{
              'ok': true,
              'status': 'denied',
              'message': 'open',
              'canRequest': true,
              'canOpenSettings': true,
              'details': <String, Object?>{'opened': true},
            },
            _ => throw StateError('unexpected ${arguments.first}'),
          };
          return ProcessResult(1, 0, jsonEncode(payload), '');
        },
      );

      const configuration = CoreRuntimeConfiguration(
        vmHost: 'localhost',
        vmPort: 8181,
        resourcesSupported: true,
        imagesSupported: true,
        dumpsSupported: false,
        dynamicRegistrySupported: false,
        saveImagesToFiles: false,
        flutterDevice: 'macos',
        stateRootDir: '/tmp/flutter_mcp_state',
      );

      final status = await service.status(
        kind: PermissionKind.visualCapture,
        policy: PermissionPolicy.checkOnly,
        configuration: configuration,
      );
      final request = await service.request(
        kind: PermissionKind.visualCapture,
        policy: PermissionPolicy.requestAlways,
        configuration: configuration,
      );
      final openSettings = await service.openSettings(
        kind: PermissionKind.visualCapture,
        policy: PermissionPolicy.checkOnly,
        configuration: configuration,
      );

      expect(status.status, equals(PermissionStatus.notDetermined));
      expect(request.status, equals(PermissionStatus.granted));
      expect(openSettings.status, equals(PermissionStatus.denied));
      expect(
        calls,
        equals(const <String>['status', 'request', 'open-settings']),
      );
    });

    test('helper cache key is stable for identical source', () {
      expect(
        helperSourceHash('same-source'),
        equals(helperSourceHash('same-source')),
      );
      expect(
        helperSourceHash('same-source'),
        isNot(equals(helperSourceHash('other-source'))),
      );
    });
  });
}
