import 'dart:io';

/// Represents a parsed Hyprland configuration with base config and dynamic sections
class HyprlandConfig {
  final String baseConfig;
  final Map<String, String> dynamicSections;
  final List<String> animations;

  const HyprlandConfig({
    required this.baseConfig,
    required this.dynamicSections,
    required this.animations,
  });

  /// Reconstructs the full config by combining base config with dynamic sections
  String buildFullConfig({
    String? decorationConfig,
    String? generalConfig,
    String? animationConfig,
  }) {
    final buffer = StringBuffer(baseConfig);
    
    if (decorationConfig != null) {
      buffer.writeln(decorationConfig);
    }
    
    if (generalConfig != null) {
      buffer.writeln(generalConfig);
    }
    
    if (animationConfig != null) {
      buffer.writeln(animationConfig);
    }
    
    return buffer.toString();
  }
}

/// Parser for Hyprland configuration files
class HyprlandConfigParser {
  static const List<String> _dynamicSections = ['decoration', 'general'];
  
  /// Parses a Hyprland config file and extracts base config from dynamic sections
  static HyprlandConfig parseConfig(String configContent) {
    final lines = configContent.split('\n');
    final baseLines = <String>[];
    final dynamicSections = <String, String>{};
    final animations = <String>[];
    
    bool inDynamicSection = false;
    String currentSection = '';
    final currentSectionLines = <String>[];
    int braceDepth = 0;

    for (final line in lines) {
      final trimmed = line.trim();

      // Handle animation lines (they're not in blocks)
      if (trimmed.startsWith('animation=')) {
        animations.add(trimmed);
        continue;
      }

      // Detect section starts
      if (trimmed.endsWith('{') && !trimmed.startsWith('#')) {
        final sectionName = _extractSectionName(trimmed);
        
        if (_isDynamicSection(sectionName)) {
          inDynamicSection = true;
          currentSection = sectionName;
          currentSectionLines.clear();
          currentSectionLines.add(line);
          braceDepth = 1;
          continue;
        }
      }

      if (inDynamicSection) {
        currentSectionLines.add(line);
        
        // Track brace depth to handle nested sections
        if (trimmed.endsWith('{')) {
          braceDepth++;
        } else if (trimmed == '}') {
          braceDepth--;
          
          if (braceDepth == 0) {
            // End of current dynamic section
            dynamicSections[currentSection] = currentSectionLines.join('\n');
            inDynamicSection = false;
            currentSection = '';
            continue;
          }
        }
      } else {
        // Include line if not in dynamic section
        baseLines.add(line);
      }
    }

    return HyprlandConfig(
      baseConfig: baseLines.join('\n'),
      dynamicSections: dynamicSections,
      animations: animations,
    );
  }

  /// Parses a config file from disk
  static Future<HyprlandConfig> parseConfigFile(String filePath) async {
    final file = File(filePath);
    if (!file.existsSync()) {
      throw FileSystemException('Config file not found', filePath);
    }
    
    final content = await file.readAsString();
    return parseConfig(content);
  }

  /// Extracts section name from a line like "decoration {" or "general {"
  static String _extractSectionName(String line) {
    final parts = line.trim().split(' ');
    return parts.isNotEmpty ? parts[0].toLowerCase() : '';
  }

  /// Checks if a section should be dynamically generated
  static bool _isDynamicSection(String sectionName) {
    return _dynamicSections.contains(sectionName);
  }

  /// Validates that all expected styling sections are present in the config
  static ConfigValidationResult validateConfig(String configContent) {
    final config = parseConfig(configContent);
    final issues = <String>[];
    final foundSections = <String>[];

    // Check for expected sections
    for (final section in _dynamicSections) {
      if (config.dynamicSections.containsKey(section)) {
        foundSections.add(section);
      }
    }

    // Check for animation definitions
    final hasAnimations = config.animations.isNotEmpty;
    if (!hasAnimations) {
      // Check if animations are defined in the base config (inline)
      final hasInlineAnimations = config.baseConfig.contains('animation=');
      if (!hasInlineAnimations) {
        issues.add('No animation definitions found');
      }
    }

    // Validate decoration section content
    if (config.dynamicSections.containsKey('decoration')) {
      final decorationContent = config.dynamicSections['decoration']!;
      final decorationIssues = _validateDecorationSection(decorationContent);
      issues.addAll(decorationIssues);
    }

    // Validate general section content
    if (config.dynamicSections.containsKey('general')) {
      final generalContent = config.dynamicSections['general']!;
      final generalIssues = _validateGeneralSection(generalContent);
      issues.addAll(generalIssues);
    }

    return ConfigValidationResult(
      isValid: issues.isEmpty,
      issues: issues,
      foundSections: foundSections,
      hasAnimations: hasAnimations || config.baseConfig.contains('animation='),
    );
  }

  /// Validates decoration section for required styling properties
  static List<String> _validateDecorationSection(String decorationContent) {
    final issues = <String>[];
    
    // Check for rounding property
    if (!decorationContent.contains('rounding =')) {
      issues.add('Missing decoration property: rounding');
    }

    // Check for blur section (not just the word "blur")
    if (!decorationContent.contains('blur {')) {
      issues.add('Missing decoration property: blur');
    } else {
      // Check for blur sub-properties only if blur section exists
      final blurProperties = ['enabled', 'passes', 'size'];
      for (final prop in blurProperties) {
        if (!decorationContent.contains('$prop =')) {
          issues.add('Missing blur property: $prop');
        }
      }
    }

    // Check for shadow section (not just the word "shadow")
    if (!decorationContent.contains('shadow {')) {
      issues.add('Missing decoration property: shadow');
    } else {
      // Check for shadow sub-properties only if shadow section exists
      final shadowProperties = ['enabled', 'range', 'render_power'];
      for (final prop in shadowProperties) {
        if (!decorationContent.contains('$prop =')) {
          issues.add('Missing shadow property: $prop');
        }
      }
    }

    return issues;
  }

  /// Validates general section for required styling properties
  static List<String> _validateGeneralSection(String generalContent) {
    final issues = <String>[];
    final requiredProperties = [
      'border_size',
      'col.active_border',
      'col.inactive_border',
      'gaps_in',
      'gaps_out',
    ];

    for (final property in requiredProperties) {
      if (!generalContent.contains(property)) {
        issues.add('Missing general property: $property');
      }
    }

    return issues;
  }

  /// Extracts all styling-related properties from a config
  static Map<String, dynamic> extractStylingProperties(String configContent) {
    final config = parseConfig(configContent);
    final styling = <String, dynamic>{};

    // Extract decoration properties
    if (config.dynamicSections.containsKey('decoration')) {
      styling['decoration'] = _extractDecorationProperties(
        config.dynamicSections['decoration']!
      );
    }

    // Extract general properties
    if (config.dynamicSections.containsKey('general')) {
      styling['general'] = _extractGeneralProperties(
        config.dynamicSections['general']!
      );
    }

    // Extract animations
    final allAnimations = <String>[];
    allAnimations.addAll(config.animations);
    
    // Also check for inline animations in base config
    final baseLines = config.baseConfig.split('\n');
    for (final line in baseLines) {
      if (line.trim().startsWith('animation=')) {
        allAnimations.add(line.trim());
      }
    }
    
    if (allAnimations.isNotEmpty) {
      styling['animations'] = allAnimations;
    }

    return styling;
  }

  /// Extracts decoration properties from decoration section
  static Map<String, dynamic> _extractDecorationProperties(String decorationContent) {
    final properties = <String, dynamic>{};
    final lines = decorationContent.split('\n');

    for (final line in lines) {
      final trimmed = line.trim();
      if (trimmed.contains('=') && !trimmed.startsWith('#')) {
        final parts = trimmed.split('=');
        if (parts.length >= 2) {
          final key = parts[0].trim();
          final value = parts.sublist(1).join('=').trim();
          properties[key] = value;
        }
      }
    }

    return properties;
  }

  /// Extracts general properties from general section
  static Map<String, dynamic> _extractGeneralProperties(String generalContent) {
    final properties = <String, dynamic>{};
    final lines = generalContent.split('\n');

    for (final line in lines) {
      final trimmed = line.trim();
      if (trimmed.contains('=') && !trimmed.startsWith('#')) {
        final parts = trimmed.split('=');
        if (parts.length >= 2) {
          final key = parts[0].trim();
          final value = parts.sublist(1).join('=').trim();
          properties[key] = value;
        }
      }
    }

    return properties;
  }
}

/// Result of config validation
class ConfigValidationResult {
  final bool isValid;
  final List<String> issues;
  final List<String> foundSections;
  final bool hasAnimations;

  const ConfigValidationResult({
    required this.isValid,
    required this.issues,
    required this.foundSections,
    required this.hasAnimations,
  });

  @override
  String toString() {
    final buffer = StringBuffer();
    buffer.writeln('Config Validation Result:');
    buffer.writeln('  Valid: $isValid');
    buffer.writeln('  Found sections: ${foundSections.join(', ')}');
    buffer.writeln('  Has animations: $hasAnimations');
    
    if (issues.isNotEmpty) {
      buffer.writeln('  Issues:');
      for (final issue in issues) {
        buffer.writeln('    - $issue');
      }
    }
    
    return buffer.toString();
  }
}
