@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
@use 'sass:string';
@use '../schemas' as *;
@use '../scoping' as std;
@use '../../base' as *;
@use '../../components' as *;
@use 'igniteui-theming/sass/color' as *;
@use 'igniteui-theming/sass/color/presets' as *;
@use 'igniteui-theming/sass/elevations' as *;
@use 'igniteui-theming/sass/elevations/presets' as elevations;
@use 'igniteui-theming/sass/utils' as *;
@use 'igniteui-theming/sass/themes' as *;
@use 'igniteui-theming/sass/themes/charts' as *;
@use 'igniteui-theming/sass/themes/schemas/components/light/button' as *;

@use '../../../../grids/themes/derived' as grid;
@use '../../../../grids/core/src/column-actions/themes/derived' as grid-column-actions;
@use '../../../../grids/core/src/filtering/excel-style/themes/derived' as grid-excel-filtering;
@use '../../../../grids/core/src/toolbar/themes/derived' as grid-toolbar;
@use '../../../../paginator/src/paginator/themes/derived' as paginator;
@use '../../../../query-builder/src/query-builder/themes/derived' as query-builder;

////
/// @group themes
/// @access public
/// @author <a href="https://github.com/simeonoff" target="_blank">Simeon Simeonoff</a>
////

/// Default noop handler for theme map transforms
/// @access private
@function theme-noop($arg) {
    @return $arg;
}

/// Generates an Ignite UI for Angular global theme.
/// @param {Map} $palette - An palette to be used by the global theme.
/// @param {Map} $schema [$light-material-schema] - The schema used as basis for styling the components.
/// @param {List} $exclude [( )] - A list of igx components to be excluded from the global theme styles.
/// @param {Number} $roundness [null] - Sets the global roundness factor (the value can be any decimal fraction between 0 and 1) for all components.
/// @param {Boolean} $elevation [true] - Turns on/off elevations for all components in the theme.
/// @param {Map} $elevations [$elevations] - The elevation map to be used by all component themes.
/// @requires $light-material-schema
/// @requires {function} is-component
/// @requires {function} is-used
@mixin theme(
    $palette,
    $schema: $light-material-schema,
    $exclude: (),
    $roundness: null,
    $elevation: true,
    $elevations: elevations.$material-elevations
) {
    @include theme-internal(
        $palette: $palette,
        $schema: $schema,
        $exclude: $exclude,
        $roundness: $roundness,
        $elevation: $elevation,
        $elevations: $elevations
    );
}

/// Generates an Ignite UI for Angular global theme.
/// @access private
/// @param {Map} $palette - An palette to be used by the global theme.
/// @param {Map} $schema [$light-schema] - The schema used as basis for styling the components.
/// @param {List} $exclude [( )] - A list of igx components to be excluded from the global theme styles.
/// @param {Number} $roundness [null] - Sets the global roundness factor (the value can be any decimal fraction between 0 and 1) for all components.
/// @param {Boolean} $elevation [true] - Turns on/off elevations for all components in the theme.
/// @param {Map} $elevations [$elevations] - The elevation map to be used by all component themes.
/// @requires $light-material-schema
/// @requires {function} is-component
/// @requires {function} is-used
@mixin theme-internal(
    $palette,
    $schema: $light-material-schema,
    $exclude: (),
    $roundness: null,
    $elevation: true,
    $elevations: elevations.$material-elevations,
    $theme-handler: meta.get-function('theme-noop')
) {
    // Stores all excluded component styles
    $excluded: ();
    $scope: if(is-root(), ':root', '&');
    $theme: map.get($schema, '_meta', 'theme');
    $variant: map.get($schema, '_meta', 'variant');

    @if not(list.index($exclude, 'palette')) {
        @include palette($palette);
    }

    @if not(list.index($exclude, 'elevations')) {
        @include elevations($elevations);
    }

    @if $elevation == false {
        #{$scope} {
            --ig-elevation-factor: 0;
        }
    }

    @if $roundness {
        #{$scope} {
            --ig-radius-factor: #{$roundness};
        }
    }

    @if $theme {
        #{$scope} {
            --ig-theme: #{$theme};
            --ig-theme-variant: #{$variant};
        }
    }

    @if list.length($exclude) > 0 {
        $excluded: is-component($exclude);
    }

    @layer ig.reset, ig.base, ig.#{$theme}, ig.derived;

    // Component tokens — emitted once per theme, gated by $exclude so a
    // consumer that only uses a handful of components isn't paying for the
    // tokens of everything else. Structural styles live in each component's
    // *.component.scss.
    @if is-used('igx-action-strip', $exclude) {
        @include std.component-tokens('igx-action-strip', 'action-strip', $schema);
    }

    @if is-used('igx-avatar', $exclude) {
        @include std.component-tokens('igx-avatar', 'avatar', $schema);
    }

    @if is-used('igx-badge', $exclude) {
        @include std.component-tokens('igx-badge', 'badge', $schema);
    }

    @if is-used('igx-banner', $exclude) {
        @include std.component-tokens('igx-banner', 'banner', $schema);
    }

    @if is-used('igx-bottom-nav', $exclude) {
        @include std.component-tokens('igx-bottom-nav', 'bottom-nav', $schema);
    }

    @if is-used('igx-button-group', $exclude) {
        @include std.component-tokens('igx-button-group', 'button-group', $schema);
    }

    @if is-used('igx-calendar', $exclude) {
        @include std.component-tokens('igx-calendar', 'calendar', $schema);
        @include std.component-tokens('igx-calendar-view--standalone', 'calendar', $schema);
        @include std.component-tokens('igx-days-view--standalone', 'calendar', $schema);
        @include std.component-tokens('igx-month-picker', 'calendar', $schema);
    }

    @if is-used('igx-card', $exclude) {
        @include std.component-tokens('igx-card', 'card', $schema);
    }

    @if is-used('igx-carousel', $exclude) {
        @include std.component-tokens('igx-carousel', 'carousel', $schema);
    }

    @if is-used('igx-circular-bar', $exclude) {
        @include std.component-tokens('igx-circular-bar', 'circular-bar', $schema);
    }

    @if is-used('igx-checkbox', $exclude) {
        @include std.component-tokens('igx-checkbox', 'checkbox', $schema);
    }

    @if is-used('igx-chip', $exclude) {
        @include std.component-tokens('igx-chip', 'chip', $schema);
    }

    @if is-used('igx-column-actions', $exclude) {
        @include std.component-tokens('igx-column-actions', 'column-actions', $schema);
    }

    @if is-used('igx-combo', $exclude) {
        @include std.component-tokens('igx-combo', 'combo', $schema);
    }

    @if is-used('igx-date-picker', $exclude) {
        @include std.component-tokens('igx-date-picker', 'date-picker', $schema);
    }

    @if is-used('igx-date-range-picker', $exclude) {
        @include std.component-tokens('igx-date-range-picker', 'date-range', $schema);
    }

    @if is-used('igx-dialog', $exclude) {
        @include std.component-tokens('igx-dialog', 'dialog', $schema);
    }

    @if is-used('igx-divider', $exclude) {
        @include std.component-tokens('igx-divider', 'divider', $schema);
    }

    @if is-used('igx-drop-down', $exclude) {
        @include std.component-tokens('igx-drop-down', 'drop-down', $schema);
    }

    @if is-used('igx-grid-excel-style-filtering', $exclude) {
        @include std.component-tokens('igx-excel-filter', 'grid-excel-filtering', $schema);
        @include std.component-tokens('igx-excel-filter__secondary', 'grid-excel-filtering', $schema);
    }

    @if is-used('igx-expansion-panel', $exclude) {
        @include std.component-tokens('igx-expansion-panel', 'expansion-panel', $schema);
    }

    @if is-used('igx-grid', $exclude) {
        @include std.component-tokens('igx-grid', 'grid', $schema);
    }

    @if is-used('igx-grid-summary', $exclude) {
        @include std.component-tokens('igx-grid-summary', 'grid-summary', $schema);
    }

    @if is-used('igx-grid-toolbar', $exclude) {
        @include std.component-tokens('igx-grid-toolbar', 'grid-toolbar', $schema);
    }

    @if is-used('igx-icon', $exclude) {
        @scope (.igx-icon) {
          :scope:is(igx-icon) {
            @include tokens(digest-schema(map.get($schema, 'icon')), $mode: 'scoped');
          }
        }
    }

    @if is-used('igx-input-group', $exclude) {
        @include std.component-tokens('igx-input-group', 'input-group', $schema);
    }

    @if is-used('igx-file-input', $exclude) {
        @include std.component-tokens('igx-file-input', 'file-input', $schema);
    }

    @if is-used('igx-linear-bar', $exclude) {
        @include std.component-tokens('igx-linear-bar', 'linear-bar', $schema);
    }

    @if is-used('igx-list', $exclude) {
        @include std.component-tokens('igx-list', 'list', $schema);
    }

    @if is-used('igx-nav-drawer', $exclude) {
        @include std.component-tokens('igx-nav-drawer', 'nav-drawer', $schema);
    }

    @if is-used('igx-navbar', $exclude) {
        @include std.component-tokens('igx-navbar', 'navbar', $schema);
    }

    @if is-used('igx-paginator', $exclude) {
        @include std.component-tokens('igx-paginator', 'paginator', $schema);
    }

    @if is-used('igx-pivot-data-selector', $exclude) {
        @include std.component-tokens('igx-pivot-data-selector', 'pivot-data-selector', $schema);
    }

    @if is-used('igx-query-builder', $exclude) {
        @include std.component-tokens('igx-advanced-filtering-dialog', 'query-builder', $schema);
        @include std.component-tokens('igx-query-builder', 'query-builder', $schema);
    }

    @if is-used('igx-radio', $exclude) {
        @include std.component-tokens('igx-radio', 'radio', $schema);
    }

    @if is-used('igx-select', $exclude) {
        @include std.component-tokens('igx-select', 'select', $schema);
    }

    @if is-used('igx-slider', $exclude) {
        @include std.component-tokens('igx-slider', 'slider', $schema);
    }

    @if is-used('igx-snackbar', $exclude) {
        @include std.component-tokens('igx-snackbar', 'snackbar', $schema);
    }

    @if is-used('igx-splitter', $exclude) {
        @include std.component-tokens('igx-splitter', 'splitter', $schema);
    }

    @if is-used('igx-stepper', $exclude) {
        @include std.component-tokens('igx-stepper', 'stepper', $schema);
    }

    @if is-used('igx-switch', $exclude) {
        @include std.component-tokens('igx-switch', 'switch', $schema);
    }

    @if is-used('igx-tabs', $exclude) {
        @include std.component-tokens('igx-tabs', 'tabs', $schema);
    }

    @if is-used('igx-time-picker', $exclude) {
        @include std.component-tokens('igx-time-picker', 'time-picker', $schema);
    }

    @if is-used('igx-toast', $exclude) {
        @include std.component-tokens('igx-toast', 'toast', $schema);
    }

    @if is-used('igx-tree', $exclude) {
        @include std.component-tokens('igx-tree-node', 'tree', $schema);
    }

    // Derived themes — emitted once per theme, gated the same way as the
    // parent component they augment, since they only apply overrides scoped
    // inside that component's own selectors.
    @if is-used('igx-grid', $exclude) {
        @include grid.derived-themes($schema, $theme);
    }

    @if is-used('igx-column-actions', $exclude) {
        @include grid-column-actions.derived-themes($schema);
    }

    @if is-used('igx-grid-toolbar', $exclude) {
        @include grid-toolbar.derived-themes($schema, $theme);
    }

    @if is-used('igx-grid-excel-style-filtering', $exclude) {
        @include grid-excel-filtering.derived-themes($schema, $theme);
    }

    @if is-used('igx-paginator', $exclude) {
        @include paginator.derived-themes($schema, $theme);
    }

    @if is-used('igx-query-builder', $exclude) {
        @include query-builder.derived-themes($schema, $theme);
    }

    @if is-used('igx-ripple', $exclude) {
        $ripple-theme-map: ripple-theme(
            $schema: $schema,
        );
        $ripple-theme-map: meta.call($theme-handler, $ripple-theme-map);
        @include ripple($ripple-theme-map);
    }

    @if is-used('igx-button', $exclude) {
        $flat-theme-map: flat-button-theme(
            $schema: $schema,
        );

        $contained-theme-map: contained-button-theme(
            $schema: $schema,
        );

        $outlined-theme-map: outlined-button-theme(
            $schema: $schema,
        );

        $fab-theme-map: fab-button-theme(
            $schema: $schema,
        );

        @include button(
            $flat: meta.call($theme-handler, $flat-theme-map),
            $contained: meta.call($theme-handler, $contained-theme-map),
            $outlined: meta.call($theme-handler, $outlined-theme-map),
            $fab:meta.call($theme-handler, $fab-theme-map)
        );
    }

    @if is-used('data-chart', $exclude) {
        $data-chart-theme-map: data-chart-theme(
            $schema: $schema,
        );
        $data-chart-theme-map: meta.call($theme-handler, $data-chart-theme-map);
        @include tokens($data-chart-theme-map, $mode: 'scoped');
    }

    @if is-used('doughnut-chart', $exclude) {
        $doughnut-chart-theme-map: doughnut-chart-theme(
            $schema: $schema,
        );
        $doughnut-chart-theme-map: meta.call(
            $theme-handler,
            $doughnut-chart-theme-map
        );
        @include tokens($doughnut-chart-theme-map, $mode: 'scoped');
    }

    @if is-used('linear-gauge', $exclude) {
        $linear-gauge-theme-map: linear-gauge-theme(
            $schema: $schema,
        );
        $linear-gauge-theme-map: meta.call(
            $theme-handler,
            $linear-gauge-theme-map
        );
        @include tokens($linear-gauge-theme-map, $mode: 'scoped');
    }

    @if is-used('radial-gauge', $exclude) {
        $radial-gauge-theme-map: radial-gauge-theme(
            $schema: $schema,
        );
        $radial-gauge-theme-map: meta.call(
            $theme-handler,
            $radial-gauge-theme-map
        );
        @include tokens($radial-gauge-theme-map, $mode: 'scoped');
    }

    @if is-used('financial-chart', $exclude) {
        $financial-chart-theme-map: financial-chart-theme(
            $schema: $schema,
        );
        $financial-chart-theme-map: meta.call(
            $theme-handler,
            $financial-chart-theme-map
        );
        @include tokens($financial-chart-theme-map, $mode: 'scoped');
    }

    @if is-used('bullet-graph', $exclude) {
        $bullet-graph-theme-map: bullet-graph-theme(
            $schema: $schema,
        );
        $bullet-graph-theme-map: meta.call(
            $theme-handler,
            $bullet-graph-theme-map
        );
        @include tokens($bullet-graph-theme-map, $mode: 'scoped');
    }

    @if is-used('category-chart', $exclude) {
        $category-chart-theme-map: category-chart-theme(
            $schema: $schema,
        );
        $category-chart-theme-map: meta.call(
            $theme-handler,
            $category-chart-theme-map
        );
        @include tokens($category-chart-theme-map, $mode: 'scoped');
    }

    @if is-used('geo-map', $exclude) {
        $geo-map-theme-map: geo-map-theme(
            $schema: $schema,
        );
        $geo-map-theme-map: meta.call($theme-handler, $geo-map-theme-map);
        @include tokens($geo-map-theme-map, $mode: 'scoped');
    }

    @if is-used('pie-chart', $exclude) {
        $pie-chart-theme-map: pie-chart-theme(
            $schema: $schema,
        );
        $pie-chart-theme-map: meta.call($theme-handler, $pie-chart-theme-map);
        @include tokens($pie-chart-theme-map, $mode: 'scoped');
    }

    @if is-used('sparkline', $exclude) {
        $sparkline-theme-map: sparkline-theme(
            $schema: $schema,
        );
        $sparkline-theme-map: meta.call($theme-handler, $sparkline-theme-map);
        @include tokens($sparkline-theme-map, $mode: 'scoped');
    }

    @if is-used('funnel-chart', $exclude) {
        $funnel-chart-theme-map: funnel-chart-theme(
            $schema: $schema,
        );
        $funnel-chart-theme-map: meta.call(
            $theme-handler,
            $funnel-chart-theme-map
        );
        @include tokens($funnel-chart-theme-map, $mode: 'scoped');
    }

    @if is-used('shape-chart', $exclude) {
        $shape-chart-theme-map: shape-chart-theme(
            $schema: $schema,
        );
        $shape-chart-theme-map: meta.call(
            $theme-handler,
            $shape-chart-theme-map
        );
        @include tokens($shape-chart-theme-map, $mode: 'scoped');
    }

    @if is-used('igc-dockmanager', $exclude) {
        $dock-manager-theme-map: dock-manager-theme(
            $schema: $schema,
        );
        $dock-manager-theme-map: meta.call(
            $theme-handler,
            $dock-manager-theme-map
        );
        @include dock-manager($dock-manager-theme-map);
    }

    @if is-used('igc-rating', $exclude) {
        $rating-theme-map: rating-theme(
            $schema: $schema,
        );
        $rating-theme-map: meta.call($theme-handler, $rating-theme-map);
        @include rating($rating-theme-map);
    }

    @if is-used('igx-highlight', $exclude) {
        $highlight-theme-map: highlight-theme(
            $schema: $schema,
        );
        $highlight-theme-map: meta.call($theme-handler, $highlight-theme-map);
        @include highlight($highlight-theme-map);
    }

    @if is-used('igx-icon-button', $exclude) {
        $flat-theme-map: flat-icon-button-theme(
            $schema: $schema,
        );

        $contained-theme-map: contained-icon-button-theme(
            $schema: $schema,
        );

        $outlined-theme-map: outlined-icon-button-theme(
            $schema: $schema,
        );

        @include icon-button(
            $flat: meta.call($theme-handler, $flat-theme-map),
            $contained: meta.call($theme-handler, $contained-theme-map),
            $outlined: meta.call($theme-handler, $outlined-theme-map),
        );
    }

    @if is-used('igx-label', $exclude) {
        $label-theme-map: label-theme(
            $schema: $schema,
        );
        $label-theme-map: meta.call($theme-handler, $label-theme-map);
        @include label($label-theme-map);
    }

    @if is-used('igx-overlay', $exclude) {
        $overlay-theme-map: overlay-theme(
            $schema: $schema,
        );
        $overlay-theme-map: meta.call($theme-handler, $overlay-theme-map);
        @include overlay($overlay-theme-map);
    }

    @if is-used('ig-scrollbar', $exclude) {
        $scrollbar-theme-map: scrollbar-theme(
            $schema: $schema,
        );
        $scrollbar-theme-map: meta.call($theme-handler, $scrollbar-theme-map);
        @include scrollbar($scrollbar-theme-map);
    }

    @if is-used('igx-tooltip', $exclude) {
        $tooltip-theme-map: tooltip-theme(
            $schema: $schema,
        );
        $tooltip-theme-map: meta.call($theme-handler, $tooltip-theme-map);
        @include tooltip($tooltip-theme-map);
    }

    @if is-used('igc-trial-watermark', $exclude) {
        $watermark-theme-map: watermark-theme(
            $schema: $schema,
        );
        $watermark-theme-map: meta.call($theme-handler, $watermark-theme-map);
        @include watermark($watermark-theme-map);
    }

    @if list.length($dropped-themes) > 0 {
        @warn string.unquote('You have excluded the following components from the theme: "#{$dropped-themes}".');
    }
}

/// A wrapper around the theme mixin. Creates a global material theme that can be used with light backgrounds.
/// @param {Map} $palette - An palette to be used by the global theme.
/// @param {List} $exclude [( )] - A list of ig components to be excluded from the global theme styles.
/// @see {mixin} theme
/// @deprecated - Use the theme mixin instead.
@mixin light-theme($palette, $exclude: (), $roundness: null, $elevation: true) {
    $gray: color($palette, gray);
    $surface: color($palette, surface);

    $_light-palette: palette(
        $primary: color($palette, primary),
        $secondary: color($palette, secondary),
        $info: color($palette, info),
        $success: color($palette, success),
        $warn: color($palette, warn),
        $error: color($palette, error),
        $surface: if($surface != #fff, $surface, #fff),
        $gray: if($gray != #9e9e9e, $gray, #000),
    );

    @include theme(
        $palette: $_light-palette,
        $schema: $light-material-schema,
        $exclude: $exclude,
        $roundness: $roundness,
        $elevation: $elevation
    );
}

/// A wrapper around the theme mixin. Creates a global material theme that can be used with dark backgrounds.
/// @param {Map} $palette - An palette to be used by the global theme.
/// @param {List} $exclude [( )] - A list of igx components to be excluded from the global theme styles.
/// @see {mixin} theme
/// @deprecated - Use the theme mixin instead.
@mixin dark-theme($palette, $exclude: (), $roundness: null, $elevation: true) {
    $gray: color($palette, gray);
    $surface: color($palette, surface);

    $_dark-palette: palette(
        $primary: color($palette, primary),
        $secondary: color($palette, secondary),
        $info: color($palette, info),
        $success: color($palette, success),
        $warn: color($palette, warn),
        $error: color($palette, error),
        $surface: if($surface != #fff, $surface, #222),
        $gray: if($gray != #9e9e9e, $gray, #fff),
    );

    @include theme(
        $palette: $_dark-palette,
        $schema: $dark-material-schema,
        $exclude: $exclude,
        $roundness: $roundness,
        $elevation: $elevation
    );
}
