// Copyright (c) Jupyter Development Team.
// Copyright (c) Microsoft Corporation.
// Distributed under the terms of the Modified BSD License.

import { css, ElementStyles } from '@microsoft/fast-element';
import {
  CheckboxOptions,
  disabledCursor,
  display,
  focusVisible,
  forcedColorsStylesheetBehavior,
  FoundationElementTemplate
} from '@microsoft/fast-foundation';
import { SystemColors } from '@microsoft/fast-web-utilities';
import {
  accentFillActive,
  accentFillFocus,
  accentFillHover,
  accentFillRest,
  bodyFont,
  controlCornerRadius,
  designUnit,
  disabledOpacity,
  errorFillActive,
  errorFillFocus,
  errorFillHover,
  errorFillRest,
  focusStrokeWidth,
  foregroundOnAccentActive,
  foregroundOnAccentHover,
  foregroundOnAccentRest,
  neutralFillInputActive,
  neutralFillInputHover,
  neutralFillInputRest,
  neutralForegroundRest,
  neutralStrokeActive,
  neutralStrokeHover,
  neutralStrokeRest,
  strokeWidth,
  typeRampBaseFontSize,
  typeRampBaseLineHeight
} from '../design-tokens.js';
import { heightNumber } from '../styles/index.js';

/**
 * Styles for Checkbox
 * @public
 */
export const checkboxStyles: FoundationElementTemplate<
  ElementStyles,
  CheckboxOptions
> = (context, definition) =>
  css`
    ${display('inline-flex')} :host {
      align-items: center;
      outline: none;
      margin: calc(${designUnit} * 1px) 0;
      /* Chromium likes to select label text or the default slot when the checkbox is
            clicked. Maybe there is a better solution here? */
      user-select: none;
    }

    .control {
      position: relative;
      width: calc((${heightNumber} / 2 + ${designUnit}) * 1px);
      height: calc((${heightNumber} / 2 + ${designUnit}) * 1px);
      box-sizing: border-box;
      border-radius: calc(${controlCornerRadius} * 1px);
      border: calc(${strokeWidth} * 1px) solid ${neutralStrokeRest};
      background: ${neutralFillInputRest};
      outline: none;
      cursor: pointer;
    }

    :host([aria-invalid='true']) .control {
      border-color: ${errorFillRest};
    }

    .label {
      font-family: ${bodyFont};
      color: ${neutralForegroundRest};
      /* Need to discuss with Brian how HorizontalSpacingNumber can work.
            https://github.com/microsoft/fast/issues/2766 */
      padding-inline-start: calc(${designUnit} * 2px + 2px);
      margin-inline-end: calc(${designUnit} * 2px + 2px);
      cursor: pointer;
      font-size: ${typeRampBaseFontSize};
      line-height: ${typeRampBaseLineHeight};
    }

    .label__hidden {
      display: none;
      visibility: hidden;
    }

    .checked-indicator {
      width: 100%;
      height: 100%;
      display: block;
      fill: ${foregroundOnAccentRest};
      opacity: 0;
      pointer-events: none;
    }

    .indeterminate-indicator {
      border-radius: calc(${controlCornerRadius} * 1px);
      background: ${foregroundOnAccentRest};
      position: absolute;
      top: 50%;
      left: 50%;
      width: 50%;
      height: 50%;
      transform: translate(-50%, -50%);
      opacity: 0;
    }

    :host(:not([disabled])) .control:hover {
      background: ${neutralFillInputHover};
      border-color: ${neutralStrokeHover};
    }

    :host(:not([disabled])) .control:active {
      background: ${neutralFillInputActive};
      border-color: ${neutralStrokeActive};
    }

    :host([aria-invalid='true']:not([disabled])) .control:hover {
      border-color: ${errorFillHover};
    }

    :host([aria-invalid='true']:not([disabled])) .control:active {
      border-color: ${errorFillActive};
    }

    :host(:${focusVisible}) .control {
      outline: calc(${focusStrokeWidth} * 1px) solid ${accentFillFocus};
      outline-offset: 2px;
    }

    :host([aria-invalid='true']:${focusVisible}) .control {
      outline-color: ${errorFillFocus};
    }

    :host([aria-checked='true']) .control {
      background: ${accentFillRest};
      border: calc(${strokeWidth} * 1px) solid ${accentFillRest};
    }

    :host([aria-checked='true']:not([disabled])) .control:hover {
      background: ${accentFillHover};
      border: calc(${strokeWidth} * 1px) solid ${accentFillHover};
    }

    :host([aria-invalid='true'][aria-checked='true']) .control {
      background-color: ${errorFillRest};
      border-color: ${errorFillRest};
    }

    :host([aria-invalid='true'][aria-checked='true']:not([disabled]))
      .control:hover {
      background-color: ${errorFillHover};
      border-color: ${errorFillHover};
    }

    :host([aria-checked='true']:not([disabled]))
      .control:hover
      .checked-indicator {
      fill: ${foregroundOnAccentHover};
    }

    :host([aria-checked='true']:not([disabled]))
      .control:hover
      .indeterminate-indicator {
      background: ${foregroundOnAccentHover};
    }

    :host([aria-checked='true']:not([disabled])) .control:active {
      background: ${accentFillActive};
      border: calc(${strokeWidth} * 1px) solid ${accentFillActive};
    }

    :host([aria-invalid='true'][aria-checked='true']:not([disabled]))
      .control:active {
      background-color: ${errorFillActive};
      border-color: ${errorFillActive};
    }

    :host([aria-checked='true']:not([disabled]))
      .control:active
      .checked-indicator {
      fill: ${foregroundOnAccentActive};
    }

    :host([aria-checked='true']:not([disabled]))
      .control:active
      .indeterminate-indicator {
      background: ${foregroundOnAccentActive};
    }

    :host([aria-checked="true"]:${focusVisible}:not([disabled])) .control {
      outline: calc(${focusStrokeWidth} * 1px) solid ${accentFillFocus};
      outline-offset: 2px;
    }

    :host([aria-invalid='true'][aria-checked="true"]:${focusVisible}:not([disabled])) .control {
      outline-color: ${errorFillFocus};
    }

    :host([disabled]) .label,
    :host([readonly]) .label,
    :host([readonly]) .control,
    :host([disabled]) .control {
      cursor: ${disabledCursor};
    }

    :host([aria-checked='true']:not(.indeterminate)) .checked-indicator,
    :host(.indeterminate) .indeterminate-indicator {
      opacity: 1;
    }

    :host([disabled]) {
      opacity: ${disabledOpacity};
    }
  `.withBehaviors(
    forcedColorsStylesheetBehavior(css`
      .control {
        forced-color-adjust: none;
        border-color: ${SystemColors.FieldText};
        background: ${SystemColors.Field};
      }
      :host([aria-invalid='true']) .control {
        border-style: dashed;
      }
      .checked-indicator {
        fill: ${SystemColors.FieldText};
      }
      .indeterminate-indicator {
        background: ${SystemColors.FieldText};
      }
      :host(:not([disabled])) .control:hover,
      .control:active {
        border-color: ${SystemColors.Highlight};
        background: ${SystemColors.Field};
      }
      :host(:${focusVisible}) .control {
        outline: calc(${focusStrokeWidth} * 1px) solid ${SystemColors.FieldText};
        outline-offset: 2px;
      }
      :host([aria-checked="true"]:${focusVisible}:not([disabled])) .control {
        outline: calc(${focusStrokeWidth} * 1px) solid ${SystemColors.FieldText};
        outline-offset: 2px;
      }
      :host([aria-checked='true']) .control {
        background: ${SystemColors.Highlight};
        border-color: ${SystemColors.Highlight};
      }
      :host([aria-checked='true']:not([disabled])) .control:hover,
      .control:active {
        border-color: ${SystemColors.Highlight};
        background: ${SystemColors.HighlightText};
      }
      :host([aria-checked='true']) .checked-indicator {
        fill: ${SystemColors.HighlightText};
      }
      :host([aria-checked='true']:not([disabled]))
        .control:hover
        .checked-indicator {
        fill: ${SystemColors.Highlight};
      }
      :host([aria-checked='true']) .indeterminate-indicator {
        background: ${SystemColors.HighlightText};
      }
      :host([aria-checked='true']) .control:hover .indeterminate-indicator {
        background: ${SystemColors.Highlight};
      }
      :host([disabled]) {
        opacity: 1;
      }
      :host([disabled]) .control {
        forced-color-adjust: none;
        border-color: ${SystemColors.GrayText};
        background: ${SystemColors.Field};
      }
      :host([disabled]) .indeterminate-indicator,
      :host([aria-checked='true'][disabled])
        .control:hover
        .indeterminate-indicator {
        forced-color-adjust: none;
        background: ${SystemColors.GrayText};
      }
      :host([disabled]) .checked-indicator,
      :host([aria-checked='true'][disabled]) .control:hover .checked-indicator {
        forced-color-adjust: none;
        fill: ${SystemColors.GrayText};
      }
    `)
  );
