import 'package:flutter/material.dart';
import 'package:flut/flut/runtime.dart';
import 'package:flut/flut/object.dart';
import 'package:flut/dart/ui.dart';

class FlutColorScheme extends FlutImmutableObject {
  final ColorScheme colorScheme;

  const FlutColorScheme(this.colorScheme) : super('ColorScheme');

  @override
  Map<String, dynamic> flutEncode() {
    final result = flutBaseProps();
    result['inversePrimary'] = FlutColor(
      colorScheme.inversePrimary,
    ).flutEncode();
    result['primary'] = FlutColor(colorScheme.primary).flutEncode();
    result['onPrimary'] = FlutColor(colorScheme.onPrimary).flutEncode();
    result['secondary'] = FlutColor(colorScheme.secondary).flutEncode();
    result['onSecondary'] = FlutColor(colorScheme.onSecondary).flutEncode();
    result['surface'] = FlutColor(colorScheme.surface).flutEncode();
    result['onSurface'] = FlutColor(colorScheme.onSurface).flutEncode();
    result['error'] = FlutColor(colorScheme.error).flutEncode();
    result['onError'] = FlutColor(colorScheme.onError).flutEncode();
    return result;
  }

  static ColorScheme? flutDecode(
    FlutRuntime runtime,
    Map<String, dynamic> data,
  ) {
    final seedColor = runtime.unpackOptionalField<Color>(data, 'seedColor');
    if (seedColor != null) {
      var scheme = ColorScheme.fromSeed(seedColor: seedColor);
      scheme = scheme.copyWith(
        inversePrimary: runtime.unpackOptionalField<Color>(
          data,
          'inversePrimary',
        ),
        primary: runtime.unpackOptionalField<Color>(data, 'primary'),
        onPrimary: runtime.unpackOptionalField<Color>(data, 'onPrimary'),
        secondary: runtime.unpackOptionalField<Color>(data, 'secondary'),
        onSecondary: runtime.unpackOptionalField<Color>(data, 'onSecondary'),
        surface: runtime.unpackOptionalField<Color>(data, 'surface'),
        onSurface: runtime.unpackOptionalField<Color>(data, 'onSurface'),
        error: runtime.unpackOptionalField<Color>(data, 'error'),
        onError: runtime.unpackOptionalField<Color>(data, 'onError'),
      );
      return scheme;
    }

    final primary = runtime.unpackOptionalField<Color>(data, 'primary');
    final onPrimary = runtime.unpackOptionalField<Color>(data, 'onPrimary');
    final secondary = runtime.unpackOptionalField<Color>(data, 'secondary');
    final onSecondary = runtime.unpackOptionalField<Color>(data, 'onSecondary');
    final surface = runtime.unpackOptionalField<Color>(data, 'surface');
    final onSurface = runtime.unpackOptionalField<Color>(data, 'onSurface');
    final error = runtime.unpackOptionalField<Color>(data, 'error');
    final onError = runtime.unpackOptionalField<Color>(data, 'onError');

    if (primary == null ||
        onPrimary == null ||
        secondary == null ||
        onSecondary == null ||
        surface == null ||
        onSurface == null ||
        error == null ||
        onError == null) {
      throw ArgumentError(
        "ColorScheme decode requires either 'seedColor' or all of "
        "'primary', 'onPrimary', 'secondary', 'onSecondary', "
        "'surface', 'onSurface', 'error', 'onError'.",
      );
    }

    return ColorScheme(
      brightness: Brightness.light,
      primary: primary,
      onPrimary: onPrimary,
      secondary: secondary,
      onSecondary: onSecondary,
      surface: surface,
      onSurface: onSurface,
      error: error,
      onError: onError,
      inversePrimary: runtime.unpackOptionalField<Color>(
        data,
        'inversePrimary',
      ),
    );
  }
}
