import 'dart:math';

/// Predefined pressure curve types.
enum PressureCurveType { linear, soft, hard, custom }

/// Maps raw pen pressure [0,1] to effective pressure [0,1] using a power curve.
///
/// - **Linear**: identity (p)
/// - **Soft**: `pow(p, 1.5)` — light touch produces small lines, needs more pressure
/// - **Hard**: `pow(p, 0.5)` — light touch already produces thick lines
/// - **Custom**: `pow(p, exponent)` where exponent is derived from [softness]
class PressureCurve {
  final PressureCurveType type;
  final double softness;

  const PressureCurve({
    this.type = PressureCurveType.linear,
    this.softness = 0.5,
  });

  /// Predefined linear curve (identity).
  static const linear = PressureCurve(type: PressureCurveType.linear);

  /// Predefined soft curve — needs more pressure to ramp up.
  static const soft = PressureCurve(
    type: PressureCurveType.soft,
    softness: 0.3,
  );

  /// Predefined hard curve — light touch already produces thick lines.
  static const hard = PressureCurve(
    type: PressureCurveType.hard,
    softness: 0.7,
  );

  /// Maps raw pressure [0,1] to effective pressure [0,1].
  double apply(double rawPressure) {
    final p = rawPressure.clamp(0.0, 1.0);
    switch (type) {
      case PressureCurveType.linear:
        return p;
      case PressureCurveType.soft:
        return pow(p, 1.5).toDouble();
      case PressureCurveType.hard:
        return pow(p, 0.5).toDouble();
      case PressureCurveType.custom:
        final exponent = softness * 2 + 0.2;
        return pow(p, exponent).toDouble();
    }
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is PressureCurve &&
          runtimeType == other.runtimeType &&
          type == other.type &&
          softness == other.softness;

  @override
  int get hashCode => type.hashCode ^ softness.hashCode;
}
