// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import 'package:flutter/widgets.dart';

class MultiColor {
  const MultiColor(this._colors) : _color = null;
  const MultiColor.single(this._color) : _colors = null;

  final List<Color>? _colors;
  final Color? _color;

  Color get color => _color != null
      ? _color!
      : _colors?.isNotEmpty ?? false
          ? _colors!.first
          : throw IndexError.withLength(
              0,
              _colors?.length ?? 0,
              message: '_color is not defined or _colors is empty.',
            );

  List<Color> get colors => _colors ?? [];

  bool get isGradient => (_colors?.length ?? 0) > 1;
  bool get isColor => _color != null || isGradient;

  static MultiColor? lerp(MultiColor? a, MultiColor? b, double t) {
    if (a == null && b == null) {
      return null;
    } else if (a == null) {
      return b;
    } else if (b == null) {
      return a;
    }
    if (a.isColor && b.isColor) {
      return MultiColor.single(Color.lerp(a.color, b.color, t));
    } else if (a.isColor && b.isGradient) {
      return MultiColor(
        b.colors
            .map((e) => Color.lerp(a.color, e, t))
            .whereType<Color>()
            .toList(),
      );
    } else if (a.isGradient && b.isColor) {
      return MultiColor(
        a.colors
            .map((e) => Color.lerp(b.color, e, t))
            .whereType<Color>()
            .toList(),
      );
    } else if (a.isGradient && b.isGradient) {
      final colors = List<Color>.empty(growable: true);
      final shortestList =
          (a.colors.length > b.colors.length) ? b.colors : a.colors;
      for (int i = 0; i < shortestList.length; i++) {
        final lerpColor = Color.lerp(a.colors[i], b.colors[i], t);
        if (lerpColor != null) {
          colors.add(lerpColor);
        }
      }
      return MultiColor(colors);
    }
    return b;
  }

  @override
  String toString() => 'MultiColor(_colors: $_colors, _color: $_color)';
}
