import 'dart:io';
import 'package:test/test.dart';
import 'package:oto/oto/agent/agent_config.dart';

void main() {
  const validBootstrapYaml = '''
agent:
  id: "agent-123"
  alias: "my-test-agent"
  enrollment_token: "token-abc-456"
edge:
  url: "https://edge.toki-labs.com:8443"
runtime:
  install_dir: "/usr/local/bin"
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';

  const validBootstrapYamlNoAlias = '''
agent:
  id: "agent-123"
  alias: ""
  enrollment_token: "token-abc-456"
edge:
  url: "https://edge.toki-labs.com:8443"
runtime:
  install_dir: "/usr/local/bin"
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';

  const validBootstrapYamlMissingAlias = '''
agent:
  id: "agent-123"
  enrollment_token: "token-abc-456"
edge:
  url: "https://edge.toki-labs.com:8443"
runtime:
  install_dir: "/usr/local/bin"
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';

  test('AgentConfig parses bootstrap config yaml', () {
    final config = AgentConfig.fromYamlContent(validBootstrapYaml);
    expect(config.agent.id, 'agent-123');
    expect(config.agent.alias, 'my-test-agent');
    expect(config.agent.enrollmentToken, 'token-abc-456');
    expect(config.edge.url, 'https://edge.toki-labs.com:8443');
    expect(config.runtime.installDir, '/usr/local/bin');
    expect(config.runtime.workspaceRoot, '/home/user/.oto/workspace');
    expect(config.runtime.logDir, '/home/user/.oto/logs');
  });

  test('AgentConfig preserves empty alias', () {
    final config = AgentConfig.fromYamlContent(validBootstrapYamlNoAlias);
    expect(config.agent.id, 'agent-123');
    expect(config.agent.alias, '');
    expect(config.agent.enrollmentToken, 'token-abc-456');
  });

  test('AgentConfig parses missing alias as null', () {
    final config = AgentConfig.fromYamlContent(validBootstrapYamlMissingAlias);
    expect(config.agent.id, 'agent-123');
    expect(config.agent.alias, isNull);
    expect(config.agent.enrollmentToken, 'token-abc-456');
  });

  test('AgentConfig rejects missing required values', () {
    const missingAgentId = '''
agent:
  alias: "my-test-agent"
  enrollment_token: "token-abc-456"
edge:
  url: "https://edge.toki-labs.com:8443"
runtime:
  install_dir: "/usr/local/bin"
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';
    expect(
        () => AgentConfig.fromYamlContent(missingAgentId),
        throwsA(isA<AgentConfigException>()
            .having((e) => e.message, 'message', contains('agent.id'))));

    const missingEnrollmentToken = '''
agent:
  id: "agent-123"
  alias: "my-test-agent"
edge:
  url: "https://edge.toki-labs.com:8443"
runtime:
  install_dir: "/usr/local/bin"
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';
    expect(
        () => AgentConfig.fromYamlContent(missingEnrollmentToken),
        throwsA(isA<AgentConfigException>().having(
            (e) => e.message, 'message', contains('agent.enrollment_token'))));

    const missingEdge = '''
agent:
  id: "agent-123"
  alias: "my-test-agent"
  enrollment_token: "token-abc-456"
runtime:
  install_dir: "/usr/local/bin"
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';
    expect(
        () => AgentConfig.fromYamlContent(missingEdge),
        throwsA(isA<AgentConfigException>()
            .having((e) => e.message, 'message', contains('edge'))));

    const missingEdgeUrl = '''
agent:
  id: "agent-123"
  alias: "my-test-agent"
  enrollment_token: "token-abc-456"
edge:
  url: ""
runtime:
  install_dir: "/usr/local/bin"
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';
    expect(
        () => AgentConfig.fromYamlContent(missingEdgeUrl),
        throwsA(isA<AgentConfigException>()
            .having((e) => e.message, 'message', contains('edge.url'))));

    const missingInstallDir = '''
agent:
  id: "agent-123"
  alias: "my-test-agent"
  enrollment_token: "token-abc-456"
edge:
  url: "https://edge.toki-labs.com:8443"
runtime:
  workspace_root: "/home/user/.oto/workspace"
  log_dir: "/home/user/.oto/logs"
''';
    expect(
        () => AgentConfig.fromYamlContent(missingInstallDir),
        throwsA(isA<AgentConfigException>().having(
            (e) => e.message, 'message', contains('runtime.install_dir'))));
  });

  test('AgentConfig rejects invalid field types', () {
    const invalidIdYaml = '''
agent:
  id: ["not-a-string"]
  enrollment_token: "token-abc"
edge:
  url: "http://edge"
runtime:
  install_dir: "/bin"
  workspace_root: "/work"
  log_dir: "/log"
''';
    expect(
        () => AgentConfig.fromYamlContent(invalidIdYaml),
        throwsA(isA<AgentConfigException>()
            .having((e) => e.message, 'message', contains('agent.id'))));

    const invalidAliasYaml = '''
agent:
  id: "agent-1"
  alias: true
  enrollment_token: "token-abc"
edge:
  url: "http://edge"
runtime:
  install_dir: "/bin"
  workspace_root: "/work"
  log_dir: "/log"
''';
    expect(
        () => AgentConfig.fromYamlContent(invalidAliasYaml),
        throwsA(isA<AgentConfigException>()
            .having((e) => e.message, 'message', contains('agent.alias'))));

    const invalidUrlYaml = '''
agent:
  id: "agent-1"
  enrollment_token: "token-abc"
edge:
  url: 12345
runtime:
  install_dir: "/bin"
  workspace_root: "/work"
  log_dir: "/log"
''';
    expect(
        () => AgentConfig.fromYamlContent(invalidUrlYaml),
        throwsA(isA<AgentConfigException>()
            .having((e) => e.message, 'message', contains('edge.url'))));
  });

  test('AgentConfig fromFile reads file correctly', () {
    final tempFile =
        File('${Directory.systemTemp.path}/agent_config_test_temp.yaml');
    tempFile.writeAsStringSync(validBootstrapYaml);

    try {
      final config = AgentConfig.fromFile(tempFile.path);
      expect(config.agent.id, 'agent-123');
      expect(config.edge.url, 'https://edge.toki-labs.com:8443');
    } finally {
      if (tempFile.existsSync()) {
        tempFile.deleteSync();
      }
    }
  });

  test('AgentConfig fromFile throws when file not found', () {
    expect(
        () => AgentConfig.fromFile('non_existent_file_path_1234.yaml'),
        throwsA(isA<AgentConfigException>().having(
            (e) => e.message, 'message', contains('does not exist at path'))));
  });
}
