import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:server_box/core/utils/ssh_config.dart';

void main() {
  group('SSHConfig Tests', () {
    late Directory tempDir;
    late File configFile;

    setUp(() async {
      // Create temporary directory for test SSH config files
      tempDir = await Directory.systemTemp.createTemp('ssh_config_test');
      configFile = File('${tempDir.path}/config');
    });

    tearDown(() async {
      // Clean up temporary files
      if (tempDir.existsSync()) {
        await tempDir.delete(recursive: true);
      }
    });

    test('configExists returns false for non-existent file', () async {
      final (_, exists) = SSHConfig.configExists('/non/existent/path');
      expect(exists, false);
    });

    test('configExists returns true for existing file', () async {
      await configFile.writeAsString('Host example\n  HostName example.com\n');
      final (_, exists) = SSHConfig.configExists(configFile.path);
      expect(exists, true);
    });

    test('parseConfig handles empty file', () async {
      await configFile.writeAsString('');
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, isEmpty);
    });

    test('parseConfig handles file with only comments', () async {
      await configFile.writeAsString('''
# This is a comment
# Another comment
''');
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, isEmpty);
    });

    test('parseConfig parses single host correctly', () async {
      await configFile.writeAsString('''
Host myserver
  HostName 192.168.1.100
  User admin
  Port 2222
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1));
      
      final server = servers.first;
      expect(server.name, 'myserver');
      expect(server.ip, '192.168.1.100');
      expect(server.user, 'admin');
      expect(server.port, 2222);
    });

    test('parseConfig handles missing HostName', () async {
      await configFile.writeAsString('''
Host myserver
  User admin
  Port 2222
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, isEmpty); // Should skip hosts without HostName
    });

    test('parseConfig uses defaults for missing optional fields', () async {
      await configFile.writeAsString('''
Host simple
  HostName example.com
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1));
      
      final server = servers.first;
      expect(server.name, 'simple');
      expect(server.ip, 'example.com');
      expect(server.user, 'root'); // default user
      expect(server.port, 22);     // default port
    });

    test('parseConfig handles multiple hosts', () async {
      await configFile.writeAsString('''
Host server1
  HostName 192.168.1.100
  User alice
  Port 22

Host server2
  HostName 192.168.1.200
  User bob
  Port 2222

Host server3
  HostName example.com
  User charlie
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(3));
      
      expect(servers[0].name, 'server1');
      expect(servers[0].ip, '192.168.1.100');
      expect(servers[0].user, 'alice');
      expect(servers[0].port, 22);
      
      expect(servers[1].name, 'server2');
      expect(servers[1].ip, '192.168.1.200');
      expect(servers[1].user, 'bob');
      expect(servers[1].port, 2222);
      
      expect(servers[2].name, 'server3');
      expect(servers[2].ip, 'example.com');
      expect(servers[2].user, 'charlie');
      expect(servers[2].port, 22);
    });

    test('parseConfig handles case insensitive keywords', () async {
      await configFile.writeAsString('''
host myserver
  hostname 192.168.1.100
  user admin
  port 2222
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1));
      
      final server = servers.first;
      expect(server.name, 'myserver');
      expect(server.ip, '192.168.1.100');
      expect(server.user, 'admin');
      expect(server.port, 2222);
    });

    test('parseConfig handles comments and empty lines', () async {
      await configFile.writeAsString('''
# Global settings
Host *
  ServerAliveInterval 60

# My development server
Host devserver
  HostName 192.168.1.50
  User developer  # development user
  Port 22

# Empty line below

Host prodserver
  HostName 10.0.0.100
  User production
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(2));
      
      expect(servers[0].name, 'devserver');
      expect(servers[0].ip, '192.168.1.50');
      expect(servers[0].user, 'developer');
      
      expect(servers[1].name, 'prodserver');
      expect(servers[1].ip, '10.0.0.100');
      expect(servers[1].user, 'production');
    });

    test('parseConfig handles wildcard hosts', () async {
      await configFile.writeAsString('''
Host *
  User defaultuser
  Port 2222

Host myserver
  HostName 192.168.1.100
  User admin
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1)); // Only named hosts, not wildcards
      
      final server = servers.first;
      expect(server.name, 'myserver');
      expect(server.ip, '192.168.1.100');
      expect(server.user, 'admin');
      expect(server.port, 22); // Uses default, not wildcard setting
    });

    test('parseConfig handles IdentityFile', () async {
      await configFile.writeAsString('''
Host keyserver
  HostName 192.168.1.100
  User admin
  IdentityFile ~/.ssh/special_key
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1));
      
      final server = servers.first;
      expect(server.keyId, '~/.ssh/special_key');
    });

    test('parseConfig handles quoted values', () async {
      await configFile.writeAsString('''
Host "server with spaces"
  HostName "192.168.1.100"
  User "admin user"
  IdentityFile "~/.ssh/key with spaces"
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1));
      
      final server = servers.first;
      expect(server.name, 'server with spaces');
      expect(server.ip, '192.168.1.100');
      expect(server.user, 'admin user');
      expect(server.keyId, '~/.ssh/key with spaces');
    });

    test('parseConfig handles invalid port values', () async {
      await configFile.writeAsString('''
Host badport
  HostName 192.168.1.100
  Port notanumber

Host goodserver
  HostName 192.168.1.200
  Port 2222
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(2));
      
      // First server should use default port due to invalid port
      expect(servers[0].name, 'badport');
      expect(servers[0].port, 22); // default port
      
      // Second server should use specified port
      expect(servers[1].name, 'goodserver');
      expect(servers[1].port, 2222);
    });

    test('parseConfig skips hosts with multiple host patterns', () async {
      await configFile.writeAsString('''
Host server1 server2
  HostName 192.168.1.100

Host singleserver
  HostName 192.168.1.200
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1)); // Only single host patterns
      
      expect(servers[0].name, 'singleserver');
    });

    test('parseConfig handles ProxyJump (ignored)', () async {
      await configFile.writeAsString('''
Host jumpserver
  HostName 192.168.1.100
  User admin
  ProxyJump bastion.example.com
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(1));
      
      final server = servers.first;
      expect(server.name, 'jumpserver');
      expect(server.ip, '192.168.1.100');
      expect(server.user, 'admin');
      // ProxyJump is ignored in current implementation
    });

    test('parseConfig returns empty list for non-existent file', () async {
      final servers = await SSHConfig.parseConfig('/non/existent/path');
      expect(servers, isEmpty);
    });

    test('parseConfig handles real-world SSH config example', () async {
      await configFile.writeAsString('''
# Default settings for all hosts
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    TCPKeepAlive yes

# Production servers
Host prod-web-01
    HostName 10.0.1.100
    User deploy
    Port 22
    IdentityFile ~/.ssh/production.pem

Host prod-db-01
    HostName 10.0.1.200
    User ubuntu
    Port 2222
    IdentityFile ~/.ssh/production.pem

# Development environment
Host dev
    HostName dev.example.com
    User developer
    Port 22

# Jump host configuration
Host bastion
    HostName bastion.example.com
    User ec2-user
    IdentityFile ~/.ssh/bastion.pem

Host internal-server
    HostName 172.16.0.50
    User admin
    ProxyJump bastion
''');
      
      final servers = await SSHConfig.parseConfig(configFile.path);
      expect(servers, hasLength(5));
      
      // Check specific servers
      final prodWeb = servers.firstWhere((s) => s.name == 'prod-web-01');
      expect(prodWeb.ip, '10.0.1.100');
      expect(prodWeb.user, 'deploy');
      expect(prodWeb.port, 22);
      expect(prodWeb.keyId, '~/.ssh/production.pem');
      
      final prodDb = servers.firstWhere((s) => s.name == 'prod-db-01');
      expect(prodDb.ip, '10.0.1.200');
      expect(prodDb.user, 'ubuntu');
      expect(prodDb.port, 2222);
      
      final dev = servers.firstWhere((s) => s.name == 'dev');
      expect(dev.ip, 'dev.example.com');
      expect(dev.user, 'developer');
      expect(dev.port, 22);
      expect(dev.keyId, isNull);
    });
  });
}