// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' as math;

import 'package:flutter/widgets.dart';

import 'theme.dart';

/// A utility class for dealing with the overlay color needed
/// to indicate elevation of surfaces.
class ElevationOverlay {
  // This class is not meant to be instantiated or extended; this constructor
  // prevents instantiation and extension.
  ElevationOverlay._();

  /// Applies a surface tint color to a given container color to indicate
  /// the level of its elevation.
  ///
  /// With Material Design 3, some components will use a "surface tint" color
  /// overlay with an opacity applied to their base color to indicate they are
  /// elevated. The amount of opacity will vary with the elevation as described
  /// in: https://m3.material.io/styles/color/the-color-system/color-roles.
  ///
  /// If [surfaceTint] is not null then the returned color will be the given
  /// [color] with the [surfaceTint] of the appropriate opacity applies to it.
  /// Otherwise it will just return [color] unmodified.
  static Color applySurfaceTint(Color color, Color? surfaceTint, double elevation) {
    if (surfaceTint != null) {
      return Color.alphaBlend(surfaceTint.withOpacity(_surfaceTintOpacityForElevation(elevation)), color);
    }
    return color;
  }

  // Calculates the opacity of the surface tint color from the elevation by
  // looking it up in the token generated table of opacities, interpolating
  // between values as needed. If the elevation is outside the range of values
  // in the table it will clamp to the smallest or largest opacity.
  static double _surfaceTintOpacityForElevation(double elevation) {
    if (elevation < _surfaceTintElevationOpacities[0].elevation) {
      // Elevation less than the first entry, so just clamp it to the first one.
      return _surfaceTintElevationOpacities[0].opacity;
    }

    // Walk the opacity list and find the closest match(es) for the elevation.
    int index = 0;
    while (elevation >= _surfaceTintElevationOpacities[index].elevation) {
      // If we found it exactly or walked off the end of the list just return it.
      if (elevation == _surfaceTintElevationOpacities[index].elevation ||
          index + 1 == _surfaceTintElevationOpacities.length) {
        return _surfaceTintElevationOpacities[index].opacity;
      }
      index += 1;
    }

    // Interpolate between the two opacity values
    final _ElevationOpacity lower = _surfaceTintElevationOpacities[index - 1];
    final _ElevationOpacity upper = _surfaceTintElevationOpacities[index];
    final double t = (elevation - lower.elevation) / (upper.elevation - lower.elevation);
    return lower.opacity + t * (upper.opacity - lower.opacity);
  }

  /// Applies an overlay color to a surface color to indicate
  /// the level of its elevation in a dark theme.
  ///
  /// If using Material Design 3, this type of color overlay is no longer used.
  /// Instead a "surface tint" overlay is used instead. See [applySurfaceTint],
  /// [ThemeData.useMaterial3] for more information.
  ///
  /// Material drop shadows can be difficult to see in a dark theme, so the
  /// elevation of a surface should be portrayed with an "overlay" in addition
  /// to the shadow. As the elevation of the component increases, the
  /// overlay increases in opacity. This function computes and applies this
  /// overlay to a given color as needed.
  ///
  /// If the ambient theme is dark ([ThemeData.brightness] is [Brightness.dark]),
  /// and [ThemeData.applyElevationOverlayColor] is true, and the given
  /// [color] is [ColorScheme.surface] then this will return a version of
  /// the [color] with a semi-transparent [ColorScheme.onSurface] overlaid
  /// on top of it. The opacity of the overlay is computed based on the
  /// [elevation].
  ///
  /// Otherwise it will just return the [color] unmodified.
  ///
  /// See also:
  ///
  ///  * [ThemeData.applyElevationOverlayColor] which controls the whether
  ///    an overlay color will be applied to indicate elevation.
  ///  * [overlayColor] which computes the needed overlay color.
  ///  * [Material] which uses this to apply an elevation overlay to its surface.
  ///  * <https://material.io/design/color/dark-theme.html>, which specifies how
  ///    the overlay should be applied.
  static Color applyOverlay(BuildContext context, Color color, double elevation) {
    final ThemeData theme = Theme.of(context);
    if (elevation > 0.0 &&
        theme.applyElevationOverlayColor &&
        theme.brightness == Brightness.dark &&
        color.withOpacity(1.0) == theme.colorScheme.surface.withOpacity(1.0)) {
      return colorWithOverlay(color, theme.colorScheme.onSurface, elevation);
    }
    return color;
  }

  /// Computes the appropriate overlay color used to indicate elevation in
  /// dark themes.
  ///
  /// If using Material Design 3, this type of color overlay is no longer used.
  /// Instead a "surface tint" overlay is used instead. See [applySurfaceTint],
  /// [ThemeData.useMaterial3] for more information.
  ///
  /// See also:
  ///
  ///  * https://material.io/design/color/dark-theme.html#properties which
  ///    specifies the exact overlay values for a given elevation.
  static Color overlayColor(BuildContext context, double elevation) {
    final ThemeData theme = Theme.of(context);
    return _overlayColor(theme.colorScheme.onSurface, elevation);
  }

  /// Returns a color blended by laying a semi-transparent overlay (using the
  /// [overlay] color) on top of a surface (using the [surface] color).
  ///
  /// If using Material Design 3, this type of color overlay is no longer used.
  /// Instead a "surface tint" overlay is used instead. See [applySurfaceTint],
  /// [ThemeData.useMaterial3] for more information.
  ///
  /// The opacity of the overlay depends on [elevation]. As [elevation]
  /// increases, the opacity will also increase.
  ///
  /// See https://material.io/design/color/dark-theme.html#properties.
  static Color colorWithOverlay(Color surface, Color overlay, double elevation) {
    return Color.alphaBlend(_overlayColor(overlay, elevation), surface);
  }

  /// Applies an opacity to [color] based on [elevation].
  static Color _overlayColor(Color color, double elevation) {
    // Compute the opacity for the given elevation
    // This formula matches the values in the spec:
    // https://material.io/design/color/dark-theme.html#properties
    final double opacity = (4.5 * math.log(elevation + 1) + 2) / 100.0;
    return color.withOpacity(opacity);
  }
}

// A data class to hold the opacity at a given elevation.
class _ElevationOpacity {
  const _ElevationOpacity(this.elevation, this.opacity);

  final double elevation;
  final double opacity;
}

// BEGIN GENERATED TOKEN PROPERTIES

// Generated code to the end of this file. Do not edit by hand.
// These defaults are generated from the Material Design Token
// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart.

// Generated version v0_92

// Surface tint opacities based on elevations according to the
// Material Design 3 specification:
//   https://m3.material.io/styles/color/the-color-system/color-roles
// Ordered by increasing elevation.
const List<_ElevationOpacity> _surfaceTintElevationOpacities = <_ElevationOpacity>[
  _ElevationOpacity(0.0, 0.0),   // Elevation level 0
  _ElevationOpacity(1.0, 0.05),  // Elevation level 1
  _ElevationOpacity(3.0, 0.08),  // Elevation level 2
  _ElevationOpacity(6.0, 0.11),  // Elevation level 3
  _ElevationOpacity(8.0, 0.12),  // Elevation level 4
  _ElevationOpacity(12.0, 0.14), // Elevation level 5
];

// END GENERATED TOKEN PROPERTIES
