/// 화면 메타데이터
class ScreenMetadata {
  final String screenName;
  final Type controllerType;
  final List<ApiEndpoint> relatedEndpoints;
  final Map<String, dynamic> screenCapabilities;
  
  ScreenMetadata({
    required this.screenName,
    required this.controllerType,
    required this.relatedEndpoints,
    required this.screenCapabilities,
  });
  
  Map<String, dynamic> toJson() => {
    'screenName': screenName,
    'controllerType': controllerType.toString(),
    'relatedEndpoints': relatedEndpoints.map((e) => e.toJson()).toList(),
    'screenCapabilities': screenCapabilities,
  };
}

/// API 엔드포인트
class ApiEndpoint {
  final String path;
  final String method;
  final String description;
  final Map<String, dynamic>? parameters;
  final Map<String, dynamic>? headers;
  
  ApiEndpoint({
    required this.path,
    required this.method,
    required this.description,
    this.parameters,
    this.headers,
  });
  
  Map<String, dynamic> toJson() => {
    'path': path,
    'method': method,
    'description': description,
    'parameters': parameters,
    'headers': headers,
  };
}

/// 테스트 가능한 기능
class TestableFeature {
  final String featureName;
  final FeatureType type;
  final List<TestCase> testCases;
  final Map<String, dynamic> metadata;
  final Type? requiredDataType;
  final Map<String, FieldConstraint>? dataConstraints;
  
  TestableFeature({
    required this.featureName,
    required this.type,
    required this.testCases,
    required this.metadata,
    this.requiredDataType,
    this.dataConstraints,
  });
}

/// 기능 타입
enum FeatureType {
  crud,
  search,
  filter,
  pagination,
  authentication,
  export,
  import,
  custom,
}

/// 테스트 케이스
class TestCase {
  final String name;
  final Future<void> Function(TestData data) execute;
  final Future<void> Function(TestData data) verify;
  final Future<void> Function(TestData data)? setup;
  final Future<void> Function(TestData data)? teardown;
  final Map<String, dynamic>? metadata;
  
  TestCase({
    required this.name,
    required this.execute,
    required this.verify,
    this.setup,
    this.teardown,
    this.metadata,
  });
}

/// 테스트 데이터
class TestData {
  final String dataType;
  final dynamic data;
  final Map<String, dynamic> metadata;
  
  TestData({
    required this.dataType,
    required this.data,
    required this.metadata,
  });
  
  Map<String, dynamic> toJson() => {
    'dataType': dataType,
    'data': data is Map || data is List ? data : data?.toJson() ?? {},
    'metadata': metadata,
  };
}

/// 데이터 요구사항
class DataRequirement {
  final Type dataType;
  final Map<String, FieldConstraint> constraints;
  final List<DataRelationship> relationships;
  final int quantity;
  
  DataRequirement({
    required this.dataType,
    required this.constraints,
    required this.relationships,
    required this.quantity,
  });
}

/// 필드 제약조건
class FieldConstraint {
  final bool required;
  final bool nullable;
  final int? minLength;
  final int? maxLength;
  final num? minValue;
  final num? maxValue;
  final String? pattern;
  final List<dynamic>? allowedValues;
  final String? defaultValue;
  
  FieldConstraint({
    this.required = true,
    this.nullable = false,
    this.minLength,
    this.maxLength,
    this.minValue,
    this.maxValue,
    this.pattern,
    this.allowedValues,
    this.defaultValue,
  });
}

/// 데이터 관계
class DataRelationship {
  final String name;
  final Type targetType;
  final RelationType type;
  final String targetId;
  final int? count;
  final Map<String, FieldConstraint>? constraints;
  
  DataRelationship({
    required this.name,
    required this.targetType,
    required this.type,
    required this.targetId,
    this.count,
    this.constraints,
  });
}

/// 관계 타입
enum RelationType {
  oneToOne,
  oneToMany,
  manyToMany,
}

/// 생성 전략
class GenerationStrategy {
  final Type dataType;
  final List<FieldGeneration> fields;
  final List<DataRelationship> relationships;
  final Map<String, dynamic> constraints;
  final int? quantity;
  
  GenerationStrategy({
    required this.dataType,
    required this.fields,
    required this.relationships,
    required this.constraints,
    this.quantity,
  });
}

/// 필드 생성 전략
class FieldGeneration {
  final String fieldName;
  final Type valueType;
  final String strategy;
  final String? prefix;
  final String? format;
  final List<dynamic>? pool;
  final String? relatedTo;
  final List<String>? values;
  final dynamic value;
  
  FieldGeneration({
    required this.fieldName,
    required this.valueType,
    required this.strategy,
    this.prefix,
    this.format,
    this.pool,
    this.relatedTo,
    this.values,
    this.value,
  });
}

/// 필드 정의
class FieldDefinition {
  final String name;
  final FieldType type;
  final dynamic Function() generator;
  final bool required;
  final bool nullable;
  
  FieldDefinition({
    required this.name,
    required this.type,
    required this.generator,
    this.required = true,
    this.nullable = false,
  });
}

/// 필드 타입
enum FieldType {
  string,
  integer,
  double,
  boolean,
  dateTime,
  date,
  time,
  object,
  array,
}

/// 테스트 결과
class TestResult {
  final String screenName;
  final DateTime startTime;
  DateTime? endTime;
  final List<FeatureTestResult> featureResults = [];
  final List<TestError> errors = [];
  final Map<String, dynamic> metrics = {};
  
  TestResult({
    required this.screenName,
    required this.startTime,
    this.endTime,
  });
  
  bool get success => errors.isEmpty && featureResults.every((r) => r.success);
  bool get passed => success; // 호환성을 위한 별칭
  
  Duration get duration => endTime != null 
    ? endTime!.difference(startTime) 
    : Duration.zero;
  
  // 테스트 카운트 관련 getter들
  int get totalTests => featureResults
      .expand((r) => r.testCaseResults)
      .length;
  
  int get passedTests => featureResults
      .expand((r) => r.testCaseResults)
      .where((r) => r.success)
      .length;
  
  int get failedTests => totalTests - passedTests;
  
  void calculateMetrics() {
    metrics['totalFeatures'] = featureResults.length;
    metrics['successfulFeatures'] = featureResults.where((r) => r.success).length;
    metrics['failedFeatures'] = featureResults.where((r) => !r.success).length;
    metrics['totalTestCases'] = featureResults
        .expand((r) => r.testCaseResults)
        .length;
    metrics['successfulTestCases'] = featureResults
        .expand((r) => r.testCaseResults)
        .where((r) => r.success)
        .length;
    metrics['averageDuration'] = _calculateAverageDuration();
  }
  
  double _calculateAverageDuration() {
    final allDurations = featureResults
        .expand((r) => r.testCaseResults)
        .map((r) => r.duration.inMilliseconds);
    
    if (allDurations.isEmpty) return 0;
    
    return allDurations.reduce((a, b) => a + b) / allDurations.length;
  }
  
  Map<String, dynamic> toJson() => {
    'screenName': screenName,
    'success': success,
    'startTime': startTime.toIso8601String(),
    'endTime': endTime?.toIso8601String(),
    'duration': duration.inMilliseconds,
    'featureResults': featureResults.map((r) => r.toJson()).toList(),
    'errors': errors.map((e) => e.toJson()).toList(),
    'metrics': metrics,
  };
}

/// 기능 테스트 결과
class FeatureTestResult {
  final String featureName;
  final DateTime startTime;
  DateTime? endTime;
  final List<TestCaseResult> testCaseResults = [];
  final Map<String, dynamic> metrics = {};
  
  FeatureTestResult({
    required this.featureName,
    required this.startTime,
    this.endTime,
  });
  
  bool get success => testCaseResults.every((r) => r.success);
  
  Duration get duration => endTime != null 
    ? endTime!.difference(startTime) 
    : Duration.zero;
  
  void calculateMetrics() {
    metrics['totalTestCases'] = testCaseResults.length;
    metrics['successfulTestCases'] = testCaseResults.where((r) => r.success).length;
    metrics['failedTestCases'] = testCaseResults.where((r) => !r.success).length;
    metrics['averageDuration'] = _calculateAverageDuration();
  }
  
  double _calculateAverageDuration() {
    if (testCaseResults.isEmpty) return 0;
    
    final totalMs = testCaseResults
        .map((r) => r.duration.inMilliseconds)
        .reduce((a, b) => a + b);
    
    return totalMs / testCaseResults.length;
  }
  
  Map<String, dynamic> toJson() => {
    'featureName': featureName,
    'success': success,
    'startTime': startTime.toIso8601String(),
    'endTime': endTime?.toIso8601String(),
    'duration': duration.inMilliseconds,
    'testCaseResults': testCaseResults.map((r) => r.toJson()).toList(),
    'metrics': metrics,
  };
}

/// 테스트 케이스 결과
class TestCaseResult {
  final String testCaseName;
  final bool success;
  final Duration duration;
  final String? error;
  final StackTrace? stackTrace;
  final Map<String, dynamic>? metadata;
  
  TestCaseResult({
    required this.testCaseName,
    required this.success,
    required this.duration,
    this.error,
    this.stackTrace,
    this.metadata,
  });
  
  Map<String, dynamic> toJson() => {
    'testCaseName': testCaseName,
    'success': success,
    'duration': duration.inMilliseconds,
    'error': error,
    'stackTrace': stackTrace?.toString(),
    'metadata': metadata,
  };
}

/// 테스트 에러
class TestError {
  final String message;
  final StackTrace? stackTrace;
  final String? feature;
  final DateTime timestamp;
  final Map<String, dynamic>? context;
  
  TestError({
    required this.message,
    this.stackTrace,
    this.feature,
    required this.timestamp,
    this.context,
  });
  
  Map<String, dynamic> toJson() => {
    'message': message,
    'stackTrace': stackTrace?.toString(),
    'feature': feature,
    'timestamp': timestamp.toIso8601String(),
    'context': context,
  };
}