import 'package:test/test.dart';
import 'package:xp_nix/src/config/hyprland_config_parser.dart';

void main() {
  group('HyprlandConfigParser', () {
    group('parseConfig', () {
      test('should parse basic config with decoration and general sections', () {
        const config = '''
# Basic Hyprland config
exec-once = waybar
\$mod = SUPER

decoration {
  rounding = 10
  blur {
    enabled = true
    passes = 2
    size = 8
  }
  shadow {
    enabled = true
    range = 15
    render_power = 3
  }
}

general {
  border_size = 2
  col.active_border = rgba(7e5fddff)
  col.inactive_border = rgba(595959aa)
  gaps_in = 5
  gaps_out = 10
}

animation=windows, 1, 7, default
animation=fade, 1, 4, default

bind = \$mod, Q, killactive
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.baseConfig, contains('exec-once = waybar'));
        expect(result.baseConfig, contains('\$mod = SUPER'));
        expect(result.baseConfig, contains('bind = \$mod, Q, killactive'));
        expect(result.baseConfig, isNot(contains('decoration {')));
        expect(result.baseConfig, isNot(contains('general {')));
        expect(result.baseConfig, isNot(contains('animation=')));

        expect(result.dynamicSections, hasLength(2));
        expect(result.dynamicSections['decoration'], contains('rounding = 10'));
        expect(result.dynamicSections['decoration'], contains('blur {'));
        expect(result.dynamicSections['general'], contains('border_size = 2'));

        expect(result.animations, hasLength(2));
        expect(result.animations[0], equals('animation=windows, 1, 7, default'));
        expect(result.animations[1], equals('animation=fade, 1, 4, default'));
      });

      test('should handle nested sections within decoration', () {
        const config = '''
decoration {
  rounding = 15
  blur {
    enabled = true
    passes = 3
    size = 12
    brightness = 1.1
    contrast = 1.2
    noise = 0.02
    vibrancy = 0.3
    vibrancy_darkness = 0.2
  }
  shadow {
    enabled = true
    range = 20
    render_power = 4
    color = rgba(7e5fddaa)
    offset = 0 0
  }
  dim_inactive = true
  dim_strength = 0.15
  inactive_opacity = 0.85
  active_opacity = 1.0
  drop_shadow = true
}
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.dynamicSections['decoration'], contains('blur {'));
        expect(result.dynamicSections['decoration'], contains('enabled = true'));
        expect(result.dynamicSections['decoration'], contains('passes = 3'));
        expect(result.dynamicSections['decoration'], contains('vibrancy_darkness = 0.2'));
        expect(result.dynamicSections['decoration'], contains('shadow {'));
        expect(result.dynamicSections['decoration'], contains('color = rgba(7e5fddaa)'));
        expect(result.dynamicSections['decoration'], contains('dim_inactive = true'));
      });

      test('should handle complex general section with gradient borders', () {
        const config = '''
general {
  border_size = 4
  col.active_border = rgba(7e5fddff) rgba(ff5100ff) rgba(00ff88ff) 45deg
  col.inactive_border = rgba(595959aa)
  gaps_in = 4
  gaps_out = 8
  resize_on_border = true
  extend_border_grab_area = 15
  allow_tearing = false
  layout = dwindle
}
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.dynamicSections['general'], contains('border_size = 4'));
        expect(result.dynamicSections['general'], contains('rgba(7e5fddff) rgba(ff5100ff) rgba(00ff88ff) 45deg'));
        expect(result.dynamicSections['general'], contains('resize_on_border = true'));
        expect(result.dynamicSections['general'], contains('extend_border_grab_area = 15'));
      });

      test('should preserve non-dynamic sections in base config', () {
        const config = '''
input {
  kb_layout = us
  follow_mouse = 1
  touchpad {
    natural_scroll = true
  }
}

misc {
  disable_hyprland_logo = true
  force_default_wallpaper = 0
}

decoration {
  rounding = 5
}

windowrule = float, ^(pavucontrol)\$
windowrule = workspace 2, ^(firefox)\$
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.baseConfig, contains('input {'));
        expect(result.baseConfig, contains('kb_layout = us'));
        expect(result.baseConfig, contains('touchpad {'));
        expect(result.baseConfig, contains('misc {'));
        expect(result.baseConfig, contains('windowrule = float'));
        expect(result.baseConfig, isNot(contains('decoration {')));

        expect(result.dynamicSections['decoration'], contains('rounding = 5'));
      });

      test('should handle config with comments and empty lines', () {
        const config = '''
# This is a comment
exec-once = waybar

# Decoration settings
decoration {
  # Rounded corners
  rounding = 10
  
  # Blur settings
  blur {
    enabled = true
    passes = 2
  }
}

# General settings
general {
  border_size = 2
  # Active border color
  col.active_border = rgba(7e5fddff)
}

# Animation settings
animation=windows, 1, 7, default
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.baseConfig, contains('# This is a comment'));
        expect(result.baseConfig, contains('exec-once = waybar'));
        expect(result.dynamicSections['decoration'], contains('# Rounded corners'));
        expect(result.dynamicSections['decoration'], contains('# Blur settings'));
        expect(result.dynamicSections['general'], contains('# Active border color'));
        expect(result.animations[0], equals('animation=windows, 1, 7, default'));
      });

      test('should handle config with no dynamic sections', () {
        const config = '''
exec-once = waybar
\$mod = SUPER

input {
  kb_layout = us
}

bind = \$mod, Q, killactive
animation=windows, 1, 7, default
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.baseConfig, contains('exec-once = waybar'));
        expect(result.baseConfig, contains('input {'));
        expect(result.baseConfig, contains('bind = \$mod, Q, killactive'));
        expect(result.dynamicSections, isEmpty);
        expect(result.animations, hasLength(1));
      });

      test('should handle inline animations in base config', () {
        const config = '''
exec-once = waybar
animation=windows, 1, 7, default
animation=fade, 1, 4, default

decoration {
  rounding = 10
}

animation=workspaces, 1, 6, default
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.animations, hasLength(3));
        expect(result.animations, contains('animation=windows, 1, 7, default'));
        expect(result.animations, contains('animation=fade, 1, 4, default'));
        expect(result.animations, contains('animation=workspaces, 1, 6, default'));
        expect(result.baseConfig, isNot(contains('animation=')));
      });
    });

    group('validateConfig', () {
      test('should validate complete config as valid', () {
        const config = '''
decoration {
  rounding = 10
  blur {
    enabled = true
    passes = 2
    size = 8
  }
  shadow {
    enabled = true
    range = 15
    render_power = 3
  }
}

general {
  border_size = 2
  col.active_border = rgba(7e5fddff)
  col.inactive_border = rgba(595959aa)
  gaps_in = 5
  gaps_out = 10
}

animation=windows, 1, 7, default
''';

        final result = HyprlandConfigParser.validateConfig(config);

        expect(result.isValid, isTrue);
        expect(result.issues, isEmpty);
        expect(result.foundSections, containsAll(['decoration', 'general']));
        expect(result.hasAnimations, isTrue);
      });

      test('should identify missing decoration properties', () {
        const config = '''
decoration {
  rounding = 10
  # Missing blur and shadow sections
}

general {
  border_size = 2
  col.active_border = rgba(7e5fddff)
  col.inactive_border = rgba(595959aa)
  gaps_in = 5
  gaps_out = 10
}
''';

        final result = HyprlandConfigParser.validateConfig(config);

        expect(result.isValid, isFalse);
        expect(result.issues, contains('Missing decoration property: blur'));
        expect(result.issues, contains('Missing decoration property: shadow'));
        expect(result.issues, contains('No animation definitions found'));
      });

      test('should identify missing blur sub-properties', () {
        const config = '''
decoration {
  rounding = 10
  blur {
    enabled = true
    # Missing passes and size
  }
  shadow {
    enabled = true
    range = 15
    render_power = 3
  }
}
''';

        final result = HyprlandConfigParser.validateConfig(config);

        expect(result.isValid, isFalse);
        expect(result.issues, contains('Missing blur property: passes'));
        expect(result.issues, contains('Missing blur property: size'));
      });

      test('should identify missing general properties', () {
        const config = '''
general {
  border_size = 2
  # Missing color and gap properties
}
''';

        final result = HyprlandConfigParser.validateConfig(config);

        expect(result.isValid, isFalse);
        expect(result.issues, contains('Missing general property: col.active_border'));
        expect(result.issues, contains('Missing general property: col.inactive_border'));
        expect(result.issues, contains('Missing general property: gaps_in'));
        expect(result.issues, contains('Missing general property: gaps_out'));
      });

      test('should accept inline animations in base config', () {
        const config = '''
exec-once = waybar
animation=windows, 1, 7, default

decoration {
  rounding = 10
  blur {
    enabled = true
    passes = 2
    size = 8
  }
  shadow {
    enabled = true
    range = 15
    render_power = 3
  }
}

general {
  border_size = 2
  col.active_border = rgba(7e5fddff)
  col.inactive_border = rgba(595959aa)
  gaps_in = 5
  gaps_out = 10
}
''';

        final result = HyprlandConfigParser.validateConfig(config);

        expect(result.isValid, isTrue);
        expect(result.hasAnimations, isTrue);
      });
    });

    group('extractStylingProperties', () {
      test('should extract all styling properties from complete config', () {
        const config = '''
decoration {
  rounding = 15
  blur {
    enabled = true
    passes = 3
    size = 12
    brightness = 1.1
  }
  shadow {
    enabled = true
    range = 20
    render_power = 4
  }
  dim_inactive = true
  active_opacity = 1.0
}

general {
  border_size = 4
  col.active_border = rgba(7e5fddff) rgba(ff5100ff) 45deg
  col.inactive_border = rgba(595959aa)
  gaps_in = 4
  gaps_out = 8
  resize_on_border = true
}

animation=windows, 1, 8, easeout, slide
animation=fade, 1, 7, easeout
''';

        final styling = HyprlandConfigParser.extractStylingProperties(config);

        expect(styling['decoration'], isA<Map<String, dynamic>>());
        expect(styling['general'], isA<Map<String, dynamic>>());
        expect(styling['animations'], isA<List<String>>());

        final decoration = styling['decoration'] as Map<String, dynamic>;
        expect(decoration['rounding'], equals('15'));
        expect(decoration['dim_inactive'], equals('true'));
        expect(decoration['active_opacity'], equals('1.0'));

        final general = styling['general'] as Map<String, dynamic>;
        expect(general['border_size'], equals('4'));
        expect(general['col.active_border'], equals('rgba(7e5fddff) rgba(ff5100ff) 45deg'));
        expect(general['resize_on_border'], equals('true'));

        final animations = styling['animations'] as List<String>;
        expect(animations, hasLength(2));
        expect(animations, contains('animation=windows, 1, 8, easeout, slide'));
        expect(animations, contains('animation=fade, 1, 7, easeout'));
      });

      test('should handle nested properties correctly', () {
        const config = '''
decoration {
  blur {
    enabled = true
    passes = 2
    size = 8
    brightness = 1.05
    contrast = 1.1
    noise = 0.01
    vibrancy = 0.2
  }
  shadow {
    enabled = true
    range = 15
    render_power = 3
    color = rgba(7e5fdd88)
    offset = 0 0
  }
}
''';

        final styling = HyprlandConfigParser.extractStylingProperties(config);
        final decoration = styling['decoration'] as Map<String, dynamic>;

        // Note: The current implementation extracts nested properties as flat key-value pairs
        // This is a limitation but matches the current parsing behavior
        expect(decoration['enabled'], equals('true'));
        expect(decoration['passes'], equals('2'));
        expect(decoration['brightness'], equals('1.05'));
        expect(decoration['vibrancy'], equals('0.2'));
        expect(decoration['color'], equals('rgba(7e5fdd88)'));
        expect(decoration['offset'], equals('0 0'));
      });

      test('should extract inline animations from base config', () {
        const config = '''
exec-once = waybar
animation=windows, 1, 7, default
bind = \$mod, Q, killactive
animation=fade, 1, 4, default

decoration {
  rounding = 10
}
''';

        final styling = HyprlandConfigParser.extractStylingProperties(config);

        expect(styling['animations'], isA<List<String>>());
        final animations = styling['animations'] as List<String>;
        expect(animations, hasLength(2));
        expect(animations, contains('animation=windows, 1, 7, default'));
        expect(animations, contains('animation=fade, 1, 4, default'));
      });

      test('should handle config with only some styling sections', () {
        const config = '''
decoration {
  rounding = 8
  blur {
    enabled = false
  }
}

# No general section
animation=workspaces, 1, 6, default
''';

        final styling = HyprlandConfigParser.extractStylingProperties(config);

        expect(styling['decoration'], isA<Map<String, dynamic>>());
        expect(styling['general'], isNull);
        expect(styling['animations'], isA<List<String>>());

        final decoration = styling['decoration'] as Map<String, dynamic>;
        expect(decoration['rounding'], equals('8'));
        expect(decoration['enabled'], equals('false'));
      });
    });

    group('buildFullConfig', () {
      test('should reconstruct config with dynamic sections', () {
        const baseConfig = '''
exec-once = waybar
\$mod = SUPER
bind = \$mod, Q, killactive
''';

        const decorationConfig = '''
decoration {
  rounding = 10
  blur {
    enabled = true
  }
}
''';

        const generalConfig = '''
general {
  border_size = 2
  gaps_in = 5
}
''';

        const animationConfig = '''
animation=windows, 1, 7, default
animation=fade, 1, 4, default
''';

        final config = HyprlandConfig(baseConfig: baseConfig, dynamicSections: {}, animations: []);

        final fullConfig = config.buildFullConfig(
          decorationConfig: decorationConfig,
          generalConfig: generalConfig,
          animationConfig: animationConfig,
        );

        expect(fullConfig, contains('exec-once = waybar'));
        expect(fullConfig, contains('\$mod = SUPER'));
        expect(fullConfig, contains('decoration {'));
        expect(fullConfig, contains('rounding = 10'));
        expect(fullConfig, contains('general {'));
        expect(fullConfig, contains('border_size = 2'));
        expect(fullConfig, contains('animation=windows, 1, 7, default'));
        expect(fullConfig, contains('animation=fade, 1, 4, default'));
      });
    });

    group('edge cases', () {
      test('should handle empty config', () {
        const config = '';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.baseConfig, isEmpty);
        expect(result.dynamicSections, isEmpty);
        expect(result.animations, isEmpty);
      });

      test('should handle config with only comments', () {
        const config = '''
# This is a comment
# Another comment
''';

        final result = HyprlandConfigParser.parseConfig(config);

        expect(result.baseConfig, contains('# This is a comment'));
        expect(result.dynamicSections, isEmpty);
        expect(result.animations, isEmpty);
      });

      test('should handle malformed sections gracefully', () {
        const config = '''
decoration {
  rounding = 10
  # Missing closing brace

general {
  border_size = 2
}
''';

        final result = HyprlandConfigParser.parseConfig(config);

        // Should still parse what it can
        expect(result.dynamicSections['general'], contains('border_size = 2'));
      });

      test('should handle properties with equals signs in values', () {
        const config = '''
general {
  col.active_border = rgba(7e5fddff) rgba(ff5100ff) rgba(00ff88ff) 45deg
  custom_prop = value=with=equals
}
''';

        final styling = HyprlandConfigParser.extractStylingProperties(config);
        final general = styling['general'] as Map<String, dynamic>;

        expect(general['col.active_border'], equals('rgba(7e5fddff) rgba(ff5100ff) rgba(00ff88ff) 45deg'));
        expect(general['custom_prop'], equals('value=with=equals'));
      });
    });
  });
}
