import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:palette_generator/palette_generator.dart';

class DynamicColorScheme {
  static const Color _defaultPrimary = Color(0xFF3C82FF); // lighter blue
  static const Color _defaultSecondary = Color(0xFF7C3AED);
  static const Color _defaultTertiary = Color(0xFF0D9488);
  static const Color _defaultSurface = Color(0xFFFFFFFF);
  static const Color _defaultBackground = Color(0xFFFAFAFA);

  // Extract dominant colors from logo image
  static Future<List<Color>> extractColorsFromImage(
      Uint8List imageBytes) async {
    try {
      // Convert bytes to image
      final codec = await ui.instantiateImageCodec(imageBytes);
      final frame = await codec.getNextFrame();
      final image = frame.image;

      // Generate palette from image
      final paletteGenerator = await PaletteGenerator.fromImage(image);

      List<Color> colors = [];

      // Add dominant colors
      if (paletteGenerator.dominantColor != null) {
        colors.add(paletteGenerator.dominantColor!.color);
      }

      // Add vibrant colors
      if (paletteGenerator.vibrantColor != null) {
        colors.add(paletteGenerator.vibrantColor!.color);
      }

      // Add muted colors
      if (paletteGenerator.mutedColor != null) {
        colors.add(paletteGenerator.mutedColor!.color);
      }

      // Add light vibrant colors
      if (paletteGenerator.lightVibrantColor != null) {
        colors.add(paletteGenerator.lightVibrantColor!.color);
      }

      // Add dark vibrant colors
      if (paletteGenerator.darkVibrantColor != null) {
        colors.add(paletteGenerator.darkVibrantColor!.color);
      }

      // Ensure we have at least 3 colors
      while (colors.length < 3) {
        colors.add(_generateComplementaryColor(
            colors.isNotEmpty ? colors.first : _defaultPrimary));
      }

      return colors.take(5).toList(); // Return top 5 colors
    } catch (e) {
      print('Error extracting colors: $e');
      return [_defaultPrimary, _defaultSecondary, _defaultTertiary];
    }
  }

  // Lightweight extraction using ImageProvider with downscaling to reduce jank
  static Future<List<Color>> extractColorsFromBytesLite(
      Uint8List imageBytes) async {
    try {
      final provider = MemoryImage(imageBytes);
      // Downscale to limit processing cost
      final resized = ResizeImage(provider, width: 256, height: 256);

      final paletteGenerator =
          await PaletteGenerator.fromImageProvider(resized);
      final List<Color> colors = [];

      if (paletteGenerator.dominantColor != null) {
        colors.add(paletteGenerator.dominantColor!.color);
      }
      if (paletteGenerator.vibrantColor != null) {
        colors.add(paletteGenerator.vibrantColor!.color);
      }
      if (paletteGenerator.mutedColor != null) {
        colors.add(paletteGenerator.mutedColor!.color);
      }
      if (paletteGenerator.lightVibrantColor != null) {
        colors.add(paletteGenerator.lightVibrantColor!.color);
      }
      if (paletteGenerator.darkVibrantColor != null) {
        colors.add(paletteGenerator.darkVibrantColor!.color);
      }

      while (colors.length < 3) {
        colors.add(_generateComplementaryColor(
            colors.isNotEmpty ? colors.first : _defaultPrimary));
      }

      return colors.take(5).toList();
    } catch (e) {
      print('Error extracting colors (lite): $e');
      return [_defaultPrimary, _defaultSecondary, _defaultTertiary];
    }
  }

  // Generate complementary color
  static Color _generateComplementaryColor(Color baseColor) {
    final hsl = HSLColor.fromColor(baseColor);
    return hsl.withHue((hsl.hue + 180) % 360).toColor();
  }

  // Generate dynamic color scheme from logo colors
  static ColorScheme generateDynamicColorScheme(List<Color> logoColors,
      {bool isDark = false}) {
    if (logoColors.isEmpty) {
      return _getDefaultColorScheme(isDark);
    }

    try {
      // Extract primary, secondary, and tertiary colors
      final primary = logoColors[0];
      final secondary = logoColors.length > 1
          ? logoColors[1]
          : _generateComplementaryColor(primary);
      final tertiary = logoColors.length > 2
          ? logoColors[2]
          : _generateComplementaryColor(secondary);

      // Generate surface and background colors
      final surface =
          isDark ? _darkenColor(primary, 0.95) : _lightenColor(primary, 0.95);
      final background =
          isDark ? _darkenColor(primary, 0.98) : _lightenColor(primary, 0.98);

      // Generate on-surface and on-background colors
      final onSurface = isDark ? Colors.white : Colors.black;
      final onBackground = isDark ? Colors.white : Colors.black;

      // Generate outline and outline variant
      final outline =
          isDark ? _lightenColor(primary, 0.3) : _darkenColor(primary, 0.3);
      final outlineVariant =
          isDark ? _lightenColor(primary, 0.2) : _darkenColor(primary, 0.2);

      // Generate surface variant
      final surfaceVariant =
          isDark ? _darkenColor(primary, 0.9) : _lightenColor(primary, 0.9);

      // Generate error, warning, success, info colors
      final error = isDark ? Color(0xFFF87171) : Color(0xFFEF4444);
      final warning = isDark ? Color(0xFFFBBF24) : Color(0xFFF59E0B);
      final success = isDark ? Color(0xFF34D399) : Color(0xFF10B981);
      final info = isDark ? Color(0xFF60A5FA) : Color(0xFF3B82F6);

      return ColorScheme(
        brightness: isDark ? Brightness.dark : Brightness.light,
        primary: primary,
        onPrimary: _getContrastColor(primary),
        primaryContainer: _generateContainerColor(primary, isDark),
        onPrimaryContainer:
            _getContrastColor(_generateContainerColor(primary, isDark)),
        secondary: secondary,
        onSecondary: _getContrastColor(secondary),
        secondaryContainer: _generateContainerColor(secondary, isDark),
        onSecondaryContainer:
            _getContrastColor(_generateContainerColor(secondary, isDark)),
        tertiary: tertiary,
        onTertiary: _getContrastColor(tertiary),
        tertiaryContainer: _generateContainerColor(tertiary, isDark),
        onTertiaryContainer:
            _getContrastColor(_generateContainerColor(tertiary, isDark)),
        surface: surface,
        onSurface: onSurface,
        surfaceVariant: surfaceVariant,
        onSurfaceVariant: _getContrastColor(surfaceVariant),
        background: background,
        onBackground: onBackground,
        outline: outline,
        outlineVariant: outlineVariant,
        error: error,
        onError: _getContrastColor(error),
        errorContainer: _generateContainerColor(error, isDark),
        onErrorContainer:
            _getContrastColor(_generateContainerColor(error, isDark)),
        shadow: isDark ? Colors.black : Colors.black12,
        scrim: isDark ? Colors.black54 : Colors.black26,
        inverseSurface: isDark ? background : surface,
        onInverseSurface: isDark ? onBackground : onSurface,
        inversePrimary:
            isDark ? _lightenColor(primary, 0.8) : _darkenColor(primary, 0.8),
      );
    } catch (e) {
      print('Error generating dynamic color scheme: $e');
      return _getDefaultColorScheme(isDark);
    }
  }

  // Get default color scheme
  static ColorScheme _getDefaultColorScheme(bool isDark) {
    if (isDark) {
      return const ColorScheme.dark(
        primary: Color(0xFF3B82F6),
        secondary: Color(0xFF8B5CF6),
        tertiary: Color(0xFF14B8A6),
      );
    } else {
      return const ColorScheme.light(
        primary: Color(0xFF2563EB),
        secondary: Color(0xFF7C3AED),
        tertiary: Color(0xFF0D9488),
      );
    }
  }

  // Generate container color
  static Color _generateContainerColor(Color baseColor, bool isDark) {
    if (isDark) {
      return _lightenColor(baseColor, 0.2);
    } else {
      return _darkenColor(baseColor, 0.9);
    }
  }

  // Lighten color
  static Color _lightenColor(Color color, double amount) {
    final hsl = HSLColor.fromColor(color);
    return hsl
        .withLightness((hsl.lightness + amount).clamp(0.0, 1.0))
        .toColor();
  }

  // Darken color
  static Color _darkenColor(Color color, double amount) {
    final hsl = HSLColor.fromColor(color);
    return hsl
        .withLightness((hsl.lightness - amount).clamp(0.0, 1.0))
        .toColor();
  }

  // Get contrast color (black or white)
  static Color _getContrastColor(Color backgroundColor) {
    final luminance = backgroundColor.computeLuminance();
    return luminance > 0.5 ? Colors.black : Colors.white;
  }

  // Generate gradient colors from logo
  static List<Color> generateGradientColors(List<Color> logoColors) {
    if (logoColors.isEmpty) {
      return [_defaultPrimary, _defaultSecondary, _defaultTertiary];
    }

    List<Color> gradientColors = [];

    // Add primary colors
    gradientColors.addAll(logoColors.take(3));

    // Generate complementary colors if needed
    while (gradientColors.length < 3) {
      final lastColor = gradientColors.last;
      gradientColors.add(_generateComplementaryColor(lastColor));
    }

    return gradientColors;
  }

  // Generate accent colors for specific UI elements
  static Map<String, Color> generateAccentColors(List<Color> logoColors) {
    if (logoColors.isEmpty) {
      return {
        'success': const Color(0xFF10B981),
        'warning': const Color(0xFFF59E0B),
        'error': const Color(0xFFEF4444),
        'info': const Color(0xFF3B82F6),
      };
    }

    final primary = logoColors[0];

    return {
      'success': _adjustColorForSuccess(primary),
      'warning': _adjustColorForWarning(primary),
      'error': _adjustColorForError(primary),
      'info': _adjustColorForInfo(primary),
    };
  }

  // Adjust colors for semantic meanings
  static Color _adjustColorForSuccess(Color baseColor) {
    final hsl = HSLColor.fromColor(baseColor);
    return hsl.withHue(120).withSaturation(0.8).withLightness(0.5).toColor();
  }

  static Color _adjustColorForWarning(Color baseColor) {
    final hsl = HSLColor.fromColor(baseColor);
    return hsl.withHue(45).withSaturation(0.9).withLightness(0.6).toColor();
  }

  static Color _adjustColorForError(Color baseColor) {
    final hsl = HSLColor.fromColor(baseColor);
    return hsl.withHue(0).withSaturation(0.8).withLightness(0.5).toColor();
  }

  static Color _adjustColorForInfo(Color baseColor) {
    final hsl = HSLColor.fromColor(baseColor);
    return hsl.withHue(210).withSaturation(0.8).withLightness(0.5).toColor();
  }
}

// Top-level helper to run in an isolate: returns list of color values (ints)
Future<List<int>> extractColorValuesFromImageBytes(Uint8List imageBytes) async {
  try {
    // Convert bytes to image
    final codec = await ui.instantiateImageCodec(imageBytes);
    final frame = await codec.getNextFrame();
    final image = frame.image;

    // Generate palette from image
    final paletteGenerator = await PaletteGenerator.fromImage(image);

    final List<int> values = [];
    if (paletteGenerator.dominantColor != null) {
      values.add(paletteGenerator.dominantColor!.color.value);
    }
    if (paletteGenerator.vibrantColor != null) {
      values.add(paletteGenerator.vibrantColor!.color.value);
    }
    if (paletteGenerator.mutedColor != null) {
      values.add(paletteGenerator.mutedColor!.color.value);
    }
    if (paletteGenerator.lightVibrantColor != null) {
      values.add(paletteGenerator.lightVibrantColor!.color.value);
    }
    if (paletteGenerator.darkVibrantColor != null) {
      values.add(paletteGenerator.darkVibrantColor!.color.value);
    }

    while (values.length < 3) {
      // Fallback complementary color generation using default primary
      values.add(DynamicColorScheme._generateComplementaryColor(
        values.isNotEmpty
            ? Color(values.first)
            : DynamicColorScheme._defaultPrimary,
      ).value);
    }

    return values.take(5).toList();
  } catch (e) {
    // Fallback to defaults
    return [
      DynamicColorScheme._defaultPrimary.value,
      DynamicColorScheme._defaultSecondary.value,
      DynamicColorScheme._defaultTertiary.value,
    ];
  }
}
