@use "./functions" as cfg;
@use "./config" as config;
@use "./tokens" as tokens;

//
@use "sass:math";
@use "sass:color";
@use "sass:list";
@use "sass:map";
@use "sass:meta";
@use "sass:string";

@use "../interact/position" as position;

/**
 * Unified CSS Custom Property Registration System
 * 
 * This module consolidates property registration logic used across the library.
 * It provides a single source of truth for @property declarations via the
 * CSS Properties and Values API (CSS Houdini).
 * 
 * Used by:
 * - lib/core/_properties.scss (orientation, transform, layout properties)
 * - lib/basic/_typed-properties.scss (UI component properties)
 * - lib/advanced/design/ (MD3 design properties)
 */

// ============================================================================
// Default initial values by CSS type
// ============================================================================

$_default-initial-values: (
    "integer": 0,
    "number": 0.0,
    "color": #0000,
    "boolean": false,
    "string": "",
    "length": 0px,
    "length-percentage": 0px,
    "angle": 0deg,
    "percentage": 0%,
    "time": 0ms,
    "frequency": 0hz,
    ) !default;

/* stylelint-disable scss/function-no-unknown */

// ============================================================================
// Mixin: Register a single CSS Custom Property
// ============================================================================

///
/// Registers a single CSS Custom Property via the Properties & Values API.
///
/// Accepts a map with keys:
/// - syntax: (string) CSS property syntax (e.g., "<color>", "<length>")
/// - initial or initial-value: (any) default value for the property
/// - inherits: (boolean) whether property inherits (defaults to true)
///
/// @example
///   @include register-property("--my-color", ("syntax": "<color>", "initial": #fff, "inherits": false));
///
@mixin register-property($name, $definition) {
    $config: if(sass(meta.type-of($definition) == "map"): $definition; else: ());

    $syntax: map.get($config, "syntax") or "<number>";
    $initial: if(sass(map.has-key($config, "initial-value")): map.get($config, "initial-value"); else: map.get($config, "initial"))
        or _option-or($_default-initial-values, $syntax, 0.0);
    $inherits: if(sass(map.has-key($config, "inherits")): map.get($config, "inherits"); else: true);

    @property #{$name} {
        @if $syntax != null {
            syntax: "#{$syntax}";
        }

        @if $inherits != null {
            inherits: $inherits;
        }

        @if $initial != null {
            initial-value: #{$initial};
        }
    }
}

// ============================================================================
// Mixin: Register multiple CSS Custom Properties at once
// ============================================================================

///
/// Registers multiple CSS Custom Properties at once from one or more maps.
///
/// Each map entry should follow the format used by `register-property`.
/// Multiple maps can be passed as arguments.
///
/// @example
///   @include register-properties((
///       "--my-color": ("syntax": "<color>", "initial": #fff),
///       "--my-size": ("syntax": "<length>", "initial": 0px),
///   ));
///
@mixin register-properties($bundles...) {
    @each $bundle in $bundles {
        @if meta.type-of($bundle)=="map" {
            @each $name, $definition in $bundle {
                @include register-property($name, $definition);
            }
        }

        @else if $bundle !=null {
            @warn "register-properties expects map entries, received #{meta.type-of($bundle)}.";
        }
    }
}

@mixin for-shell($shell-id) {
    :is(html, body):has([data-shell="#{$shell-id}"]) {
        @content;
    }
}

@mixin for-view($view-id) {
    :is(html, body):has([data-view="#{$view-id}"]) {
        @content;
    }
}

@mixin for-shell-view($shell-id, $view-id) {
    :is(html, body):has([data-shell="#{$shell-id}"] [data-view="#{$view-id}"]) {
        @content;
    }
}

@mixin when-state($selector) {
    :is(html, body):has(#{$selector}) {
        @content;
    }
}

@mixin component-styles($selector) {
    :where(#{$selector}) {
        @content;
    }
}

@mixin respond-to($breakpoint) {
    $breakpoints: (
        "sm": 640px,
        "md": 768px,
        "lg": 1024px,
        "xl": 1280px,
    );

@if map-has-key($breakpoints, $breakpoint) {
    @media (min-width: map-get($breakpoints, $breakpoint)) {
        @content;
    }
}

@else {
    @warn "Breakpoint '#{$breakpoint}' not found";
}
}

@mixin container-query($size, $direction: min-width) {
    @container (#{$direction}: #{cfg.config("container-sizes", $size)}) {
        @content;
    }
}

@mixin media-query($size, $direction: min-width) {
    @media (#{$direction}: #{cfg.config("breakpoints", $size)}) {
        @content;
    }
}

@mixin responsive-spacing($property, $sizes) {
    @each $breakpoint, $size in $sizes {
        @if $breakpoint =="base" {
            #{$property}: cfg.config("spacing", $size);
        }

        @else {
            @include container-query($breakpoint) {
                #{$property}: cfg.config("spacing", $size);
            }
        }
    }
}

@mixin flex($direction: row, $align: stretch, $justify: flex-start, $wrap: nowrap) {
    display: flex;
    flex-direction: $direction;
    align-items: $align;
    justify-content: $justify;
    flex-wrap: $wrap;
}

@mixin grid($columns: 1, $rows: auto, $gap: 0) {
    display: grid;
    grid-template-columns: $columns;
    grid-template-rows: $rows;
    gap: $gap;
}

@mixin center-flex {
    @include flex(row, center, center);
}

@mixin flex-center {
    display: flex;
    align-items: center;
    justify-content: center;
}

@mixin flex-between {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

@mixin flex-column {
    display: flex;
    flex-direction: column;
}

@mixin stack($direction: column, $gap: var(--space-md)) {
    display: flex;
    flex-direction: $direction;
    gap: $gap;
}

@mixin logical-size($block-size: auto, $inline-size: auto, $max-block-size: none, $max-inline-size: none) {
    @if $block-size !=auto {
        block-size: $block-size;
    }

    @if $inline-size !=auto {
        inline-size: $inline-size;
    }

    @if $max-block-size !=none {
        max-block-size: $max-block-size;
    }

    @if $max-inline-size !=none {
        max-inline-size: $max-inline-size;
    }
}

@mixin logical-spacing($property,
    $block: 0,
    $inline: 0,
    $block-start: null,
    $block-end: null,
    $inline-start: null,
    $inline-end: null) {
    @if $block-start !=null {
        #{$property}-block-start: $block-start;
    }

    @if $block-end !=null {
        #{$property}-block-end: $block-end;
    }

    @if $inline-start !=null {
        #{$property}-inline-start: $inline-start;
    }

    @if $inline-end !=null {
        #{$property}-inline-end: $inline-end;
    }

    @if $block-start ==null and $block-end ==null and $block !=0 {
        #{$property}-block: $block;
    }

    @if $inline-start ==null and $inline-end ==null and $inline !=0 {
        #{$property}-inline: $inline;
    }
}

@mixin logical-border($width: 1px, $style: solid, $color: currentColor, $sides: all) {
    @if $sides =="all" {
        border: $width $style $color;
    }

    @else if $sides =="block" {
        border-block: $width $style $color;
    }

    @else if $sides =="inline" {
        border-inline: $width $style $color;
    }

    @else if $sides =="block-start" {
        border-block-start: $width $style $color;
    }

    @else if $sides =="block-end" {
        border-block-end: $width $style $color;
    }

    @else if $sides =="inline-start" {
        border-inline-start: $width $style $color;
    }

    @else if $sides =="inline-end" {
        border-inline-end: $width $style $color;
    }
}

@mixin typography($size: base, $weight: normal, $line-height: normal, $letter-spacing: normal) {
    font-size: cfg.config("typography", "font-size", $size);
    font-weight: cfg.config("typography", "font-weight", $weight);
    line-height: cfg.config("typography", "line-height", $line-height);
    letter-spacing: cfg.config("typography", "letter-spacing", $letter-spacing);
}

@mixin font-family($family: sans) {
    font-family: cfg.config("typography", "font-family", $family);
}

@mixin truncate($lines: 1) {
    @if $lines ==1 {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    @else {
        display: -webkit-box;
        -webkit-line-clamp: $lines;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }
}

@mixin text-truncate {
    @include truncate(1);
}

@mixin text-clamp($lines: 2) {
    @include truncate($lines);
}

@mixin heading($level: 1) {
    font-weight: var(--font-weight-semibold);
    line-height: var(--leading-tight);
    margin-block-start: 0;
    margin-block-end: 0;

    @if $level ==1 {
        font-size: var(--text-3xl);
    }

    @else if $level ==2 {
        font-size: var(--text-2xl);
    }

    @else if $level ==3 {
        font-size: var(--text-xl);
    }

    @else if $level ==4 {
        font-size: var(--text-lg);
    }

    @else if $level ==5 {
        font-size: var(--text-md);
    }

    @else {
        font-size: var(--text-base);
    }
}

@mixin interactive($cursor: pointer, $touch-action: manipulation, $focus-ring: true) {
    cursor: $cursor;
    touch-action: $touch-action;
    user-select: none;
    -webkit-tap-highlight-color: transparent;

    @if $focus-ring {
        &:focus-visible {
            outline: 2px solid cfg.config("colors", "focus");
            outline-offset: 2px;
        }
    }

    &:disabled,
    &[aria-disabled="true"] {
        cursor: not-allowed;
        opacity: 0.6;
        pointer-events: none;
    }
}

@mixin interactive-states($hover-bg: null, $active-bg: null, $scale: 1.02) {
    transition: all cfg.config("effects", "motion-fast");

    &:hover {
        @if $hover-bg !=null {
            background-color: $hover-bg;
        }

        @if $scale !=1 {
            transform: scale($scale);
        }
    }

    &:active {
        @if $active-bg !=null {
            background-color: $active-bg;
        }

        transform: scale(0.98);
    }
}

@mixin focus-ring($color: cfg.config("colors", "focus"), $width: 2px, $offset: 2px) {
    &:focus-visible {
        outline: $width solid $color;
        outline-offset: $offset;
    }
}

@mixin hover-lift($amount: -2px) {
    transition: transform var(--transition-normal);

    &:hover {
        transform: translateY($amount);
    }
}

@mixin button-reset {
    appearance: none;
    border: none;
    background: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;

    &:disabled {
        cursor: not-allowed;
    }
}

@mixin scrollbar-base($size, $thumb-color, $track-color, $radius) {
    scrollbar-width: thin;
    scrollbar-color: $thumb-color $track-color;

    &::-webkit-scrollbar {
        inline-size: $size;
        block-size: $size;
    }

    &::-webkit-scrollbar-thumb {
        background-color: $thumb-color;
        border-radius: $radius;
    }

    &::-webkit-scrollbar-track {
        background-color: $track-color;
    }
}

@mixin scrollbar($size: 8px, $thumb-color: rgba(0, 0, 0, 0.3), $track-color: transparent) {
    @include scrollbar-base($size, $thumb-color, $track-color, cfg.config("shape", "border-radius", "full"));
}

@mixin custom-scrollbar($width: 8px, $thumb: var(--color-border-strong), $track: transparent) {
    @include scrollbar-base($width, $thumb, $track, math.div($width, 2));
}

@mixin hide-scrollbar {
    scrollbar-width: none;
    -ms-overflow-style: none;

    &::-webkit-scrollbar {
        display: none;
    }
}

@mixin focus-ring-alias($color: cfg.config("colors", "focus"), $width: 2px, $offset: 2px) {
    @include focus-ring($color, $width, $offset);
}

@mixin aspect-ratio($ratio) {
    aspect-ratio: $ratio;
}

@mixin md-break($before: auto, $inside: auto, $after: auto) {
    break-before: $before;
    break-inside: $inside;
    break-after: $after;
}

@mixin md-heading-print($scale, $padding: null) {
    $resolved-padding: sass(if(sass($padding == null): cfg.config("heading", "padding"); else: $padding));
    $line-height: cfg.config("layout", "line-height");
    $h-size: calc(3 - clamp(1, sqrt($scale) * 0.9, 2));

    font-weight: bold;
    font-size: calc($h-size * 1em);
    padding-inline: $resolved-padding;
    margin-block-end: calc($h-size * 0.333em);
    margin-block-start: calc($h-size * 0.5em);
    display: block;
    line-height: $line-height;
    text-align: start;

    @include md-break(auto, avoid-page, avoid-page);
}

@mixin md-table-cell($padding: null) {
    $resolved-padding: sass(if(sass($padding == null): cfg.config("table", "cell-padding"); else: $padding));

    padding: $resolved-padding;
    white-space: normal;
}

@mixin md-font-smoothing($mode: always) {
    font-smooth: $mode !important;
    -webkit-font-smoothing: sass(if(sass($mode == always): subpixel-antialiased; else: antialiased)) !important;
    -moz-osx-font-smoothing: sass(if(sass($mode == always): auto; else: grayscale)) !important;
}

@mixin md-interactive-area($align: null, $touch: manipulation) {
    touch-action: $touch;
    pointer-events: auto;
    user-select: text;

    @if $align !=null {
        text-align: $align;
    }
}

@mixin md-surface-root($align: start, $touch: manipulation) {
    color-scheme: inherit;
    font-size: inherit;
    isolation: isolate;

    @include md-interactive-area($align, $touch);
}

@mixin md-children-inherit($selector, $block-size: auto 1em) {
    #{$selector} {
        color-scheme: inherit;
    }
}

@mixin md-scrollbars($size: null) {
    $scroll-size: sass(if(sass($size == null): cfg.config("scrollbar", "size"); else: $size));
    // border-radius is a token map; pick one scalar (matches @mixin scrollbar).
    $radius: cfg.radius("full");

    @include scrollbar-base($scroll-size, var(--color-scrollbar), transparent, $radius);
}

@mixin breakpoint($size) {
    @if $size =="xs" {
        @media (max-width: 480px) {
            @content;
        }
    }

    @else if $size =="sm" {
        @media (max-width: 640px) {
            @content;
        }
    }

    @else if $size =="md" {
        @media (max-width: 768px) {
            @content;
        }
    }

    @else if $size =="lg" {
        @media (max-width: 1024px) {
            @content;
        }
    }

    @else if $size =="xl" {
        @media (max-width: 1280px) {
            @content;
        }
    }

    @else if $size =="2xl" {
        @media (max-width: 1536px) {
            @content;
        }
    }

    @else {
        @warn "Unknown breakpoint: #{$size}";
    }
}

@mixin breakpoint-up($size) {
    @if $size =="sm" {
        @media (min-width: 640px) {
            @content;
        }
    }

    @else if $size =="md" {
        @media (min-width: 768px) {
            @content;
        }
    }

    @else if $size =="lg" {
        @media (min-width: 1024px) {
            @content;
        }
    }

    @else if $size =="xl" {
        @media (min-width: 1280px) {
            @content;
        }
    }

    @else if $size =="2xl" {
        @media (min-width: 1536px) {
            @content;
        }
    }

    @else {
        @warn "Unknown breakpoint: #{$size}";
    }
}

@mixin print {
    @media print {
        @content;
    }
}

@mixin reduced-motion {
    @media (prefers-reduced-motion: reduce) {
        @content;
    }
}

@mixin dark-mode {
    @media (prefers-color-scheme: dark) {
        @content;
    }
}

@mixin card {
    background-color: var(--color-surface-elevated);
    border-radius: var(--card-radius);
    box-shadow: var(--card-shadow);
    padding: var(--card-padding);
}

@mixin overlay($bg: var(--modal-backdrop-bg)) {
    @include position.fixed-fill;
    background-color: $bg;
    z-index: var(--z-modal-backdrop);
}

@mixin fade-in($duration: var(--transition-normal)) {
    animation: fade-in $duration ease-out;
}

@mixin slide-in($direction: bottom, $distance: 1rem, $duration: var(--transition-normal)) {
    --slide-distance: #{$distance};
    animation: slide-in-#{$direction} $duration ease-out;
}

//
@mixin when-hover($selector: "&") {
    @media (hover: hover) and (pointer: fine) { #{$selector}:hover { @content; } }
    @media (hover: none) and (pointer: coarse) { #{$selector}:active { @content; } }
}

//
@mixin when-active($selector: "&") {
    @media (hover: hover) and (pointer: fine) { #{$selector}:active { @content; } }
}

//
@mixin when-focus($selector: "&") {
    @media (hover: hover) and (pointer: fine) { #{$selector}:focus-visible { @content; } }
    @media (hover: none) and (pointer: coarse) { #{$selector}:focus { @content; } }
}

//
@mixin when-focus-visible($selector: "&") {
    @media (hover: hover) and (pointer: fine) { #{$selector}:focus-visible { @content; } }
    @media (hover: none) and (pointer: coarse) { #{$selector}:focus-visible { @content; } }
}

//
@mixin when-disabled($selector: "&") {
    @media (hover: hover) and (pointer: fine) { #{$selector}:disabled, #{$selector}[aria-disabled="true"] { @content; } }
    @media (hover: none) and (pointer: coarse) { #{$selector}:disabled, #{$selector}[aria-disabled="true"] { @content; } }
}

//
@mixin when-selected($selector: "&") {
    @media (hover: hover) and (pointer: fine) { #{$selector}::selection, #{$selector}:checked, #{$selector}[aria-selected="true"] { @content; } }
    @media (hover: none) and (pointer: coarse) { #{$selector}::selection, #{$selector}:checked, #{$selector}[aria-selected="true"] { @content; } }
}

//
@mixin when-autofill($selector: "&") {
    #{$selector}:-webkit-autofill { @content; }
    #{$selector}:autofill { @content; }
    #{$selector}:auto-fill { @content; }
}

@mixin hover($selector: "&") {
    @include when-hover { #{$selector}:hover { @content; } }
    @include when-active { #{$selector}:active { @content; } }
}

@mixin line-clamp($lines) {
    display: -webkit-box;
    -webkit-line-clamp: $lines;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

$spaces: (
    "0": 0,
    "xs": cfg.config("spacing", "xs"),
    "sm": cfg.config("spacing", "sm"),
    "md": cfg.config("spacing", "md"),
    "lg": cfg.config("spacing", "lg"),
    "xl": cfg.config("spacing", "xl"),
    "2xl": cfg.config("spacing", "2xl"),
    "3xl": cfg.config("spacing", "3xl")
);
