@use "lib";
@use "sass:map";
@use "sass:math";
@use "sass:meta";

// ------------------ //
//  Global Variables  //
// ------------------ //

$baseline-ratio: null !default;

@if not lib.is-valid-baseline-ratio($baseline-ratio) {
  @error "Invalid $baseline-ratio: #{meta.inspect($baseline-ratio)}. The value must be a decimal between 0 and 1 (exclusive).";
}

$rhythm-size: 8px !default;

@if meta.type-of($rhythm-size) != number or not lib.has-valid-unit($rhythm-size) {
  @error "Invalid $rhythm-size: #{meta.inspect($rhythm-size)}. The value must be a number in an absolute length unit or the rem unit.";
}

$rem-size: 16px !default;

@if meta.type-of($rem-size) != number or not lib.has-valid-unit($rem-size) {
  @error "Invalid $rem-size: #{meta.inspect($rem-size)}. The value must be a number in an absolute length unit or the rem unit.";
}

$__config: (
  baseline-ratio: $baseline-ratio,
  rhythm-size: $rhythm-size,
  rem-size: $rem-size
);

// ------------------ //
//  Rhythm Functions  //
// ------------------ //

@function rhythm($rhythms, $offset: 0) {
  $_rhythms: lib.ensure-valid-rhythms($rhythms);
  $_height: $rhythm-size * $_rhythms;
  $_offset: lib.ensure-valid-offset($offset);

  @return lib.calc-height-with-offset($_height, $_offset);
}

@function baseline-top($font-map, $rhythms, $offset: 0) {
  $_font-map: lib.ensure-valid-font-map($font-map);
  $_rhythms: lib.ensure-valid-rhythms($rhythms);
  $_height: $rhythm-size * $_rhythms - lib.calc-baseline-above-height($_font-map, $__config);
  $_offset: lib.ensure-valid-offset($offset);

  @return lib.calc-height-with-offset($_height, $_offset);
}

@function baseline-bottom($font-map, $rhythms, $offset: 0) {
  $_font-map: lib.ensure-valid-font-map($font-map);
  $_rhythms: lib.ensure-valid-rhythms($rhythms);
  $_height: $rhythm-size * $_rhythms - lib.calc-baseline-below-depth($_font-map, $__config);
  $_offset: lib.ensure-valid-offset($offset);

  @return lib.calc-height-with-offset($_height, $_offset);
}

@function baseline-between($font-map-above, $font-map-below, $rhythms, $offset: 0) {
  $_font-map-above: lib.ensure-valid-font-map($font-map-above);
  $_font-map-below: lib.ensure-valid-font-map($font-map-below);
  $_rhythms: lib.ensure-valid-rhythms($rhythms);
  $_height: baseline-bottom($_font-map-above, $_rhythms) - lib.calc-baseline-above-height($_font-map-below, $__config);
  $_offset: lib.ensure-valid-offset($offset);

  @return lib.calc-height-with-offset($_height, $_offset);
}

@function rhythm-top($font-map, $rhythms, $offset: 0) {
  @return baseline-bottom($font-map, $rhythms, $offset);
}

@function rhythm-bottom($font-map, $rhythms, $offset: 0) {
  @return baseline-top($font-map, $rhythms, $offset);
}

// -------- //
//  Mixins  //
// -------- //

@mixin font($font-map, $spacing-map: ()) {
  $_font-map: lib.ensure-valid-font-map($font-map);

  font-size: map.get($_font-map, font-size);
  line-height: $rhythm-size * map.get($_font-map, line-height);

  @each $_property in map.keys(map.remove($_font-map, font-size, line-height, baseline-ratio)) {
    #{$_property}: map.get($_font-map, $_property);
  }

  @each $_property, $_value in $spacing-map {
    $_result: null;
    $_function-name: lib.first($_value);
    $_function-args: lib.rest($_value);

    @if $_property == "margin-top" or $_property == "padding-top" {
      @if $_function-name == "baseline-top" {
        $_result: meta.call(meta.get-function($_function-name), $_font-map, $_function-args...);
      } @else if $_function-name == "rhythm" {
        $_result: meta.call(meta.get-function($_function-name), $_function-args...);
      } @else if $_function-name == "baseline-between" {
        $_font-map-above: lib.first($_function-args);
        $_rest-args: lib.rest($_function-args);
        $_result: meta.call(meta.get-function($_function-name), $_font-map-above, $_font-map, $_rest-args...);
      } @else {
        @error "Unsupported function #{meta.inspect($_function-name)} in #{meta.inspect($_property)}. Supported functions: rhythm, baseline-top, baseline-between.";
      }
    } @else if $_property == "margin-bottom" or $_property == "padding-bottom" {
      @if $_function-name == "baseline-bottom" {
        $_result: meta.call(meta.get-function($_function-name), $_font-map, $_function-args...);
      } @else if $_function-name == "rhythm" {
        $_result: meta.call(meta.get-function($_function-name), $_function-args...);
      } @else if $_function-name == "baseline-between" {
        $_result: meta.call(meta.get-function($_function-name), $_font-map, $_function-args...);
      } @else {
        @error "Unsupported function #{meta.inspect($_function-name)} in #{meta.inspect($_property)}. Supported functions: rhythm, baseline-bottom, baseline-between.";
      }
    } @else {
      @error "Unsupported property #{meta.inspect($_property)} in #{meta.inspect($spacing-map)}.";
    }

    @if ($_property == "padding-top" or $_property == "padding-bottom") and $_result < 0 {
      @error "The calculated #{$_property} value (#{$_result}) is negative. Please update your rhythm counts to ensure a non-negative value.";
    }

    #{$_property}: $_result;
  }
}

@mixin draw-rhythms($color: rgb(255 120 120 / 25%)) {
  :root {
    position: relative;

    &::after {
      position: absolute;
      inset: 0;
      z-index: 2147483647; // max 32-bit signed integer, ensures overlay is always on top
      pointer-events: none;
      content: "";
      background-image: linear-gradient(to bottom, $color $rhythm-size, transparent $rhythm-size);
      background-size: 100% ($rhythm-size * 2);
    }
  }
}
