import { __decorate } from "tslib";
import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query, state } from 'lit/decorators.js';
import { HasSlotController } from '../internal/slot';
import { html } from 'lit';
import { watch } from '../internal/watch';
import NileElement from '../internal/nile-element';
import styles from './nile-radio-group.css';
import { Nile_Events } from '../internal/enum';
/**
 * @summary Radio groups are used to group multiple [radios](/components/radio) or [radio buttons](/components/radio-button) so they function as a single form control.
 *
 * @dependency nile-button-group
 *
 * @slot - The default slot where `<nile-radio>` or `<nile-radio-button>` elements are placed.
 * @slot label - The radio group's label. Required for proper accessibility. Alternatively, you can use the `label`
 *  attribute.
 *
 * @event change - Emitted when the radio group's selected value changes.
 * @event input - Emitted when the radio group receives user input.
 * @event invalid - Emitted when the form control has been checked for validity and its constraints aren't satisfied.
 * @csspart button-group - The button group that wraps radio buttons.
 * @csspart button-group__base - The button group's `base` part.
 */
let NileRadioGroup = class NileRadioGroup extends NileElement {
    constructor() {
        super(...arguments);
        this.hasSlotController = new HasSlotController(this, 'help-text', 'label');
        this.customValidityMessage = '';
        this.hasButtonGroup = false;
        this.defaultValue = '';
        /**
         * The radio group's label. Required for proper accessibility. If you need to display HTML, use the `label` slot
         * instead.
         */
        this.label = '';
        /** The name of the radio group, submitted as a name/value pair with form data. */
        this.name = 'option';
        /** The current value of the radio group, submitted as a name/value pair with form data. */
        this.value = '';
        /**
         * By default, form controls are associated with the nearest containing `<form>` element. This attribute allows you
         * to place the form control outside of a form and associate it with the form that has this `id`. The form must be in
         * the same document or shadow root for this to work.
         */
        this.form = '';
        /** Ensures a child radio is checked before allowing the containing form to submit. */
        this.required = false;
        /** Used to show radio in inline or not */
        this.labelInline = false;
        /** Used to disabled or not */
        this.disabled = false;
        this.helpText = '';
        this.errorMessage = '';
        /** The radio's labelborder for whole gp. */
        this.islabelborder = false;
        /** Allow the radio to be unchecked. */
        this.allowUncheckGroup = false;
    }
    connectedCallback() {
        super.connectedCallback();
        this.defaultValue = this.value;
        this.handleInitialDisabledState();
        this.emit('nile-init');
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.emit('nile-destroy');
    }
    getAllRadios() {
        return [...this.querySelectorAll('nile-radio')];
    }
    handleRadioClick(event) {
        const target = event.target.closest('nile-radio');
        const radios = this.getAllRadios();
        const oldValue = this.value;
        if (target.disabled || this.disabled) {
            return;
        }
        this.value = target.value;
        if (!this.allowUncheckGroup) {
            radios.forEach(radio => {
                radio.checked = radio === target;
            });
        }
        if (!this.allowUncheckGroup && this.value !== oldValue) {
            this.emit('change', { value: this.value });
            this.emit('input');
            this.emit(Nile_Events.NILE_CHANGE, { value: this.value });
            this.emit(Nile_Events.NILE_INPUT, { value: this.value });
        }
        else if (this.allowUncheckGroup) {
            this.emit('change', { value: this.value, checked: target.checked });
            this.emit('input');
            this.emit(Nile_Events.NILE_CHANGE, { value: this.value, checked: target.checked });
            this.emit(Nile_Events.NILE_INPUT, { value: this.value, checked: target.checked });
        }
    }
    updated(changedProperties) {
        super.updated(changedProperties);
        if (changedProperties.has('allowUncheckGroup')) {
            if (this.allowUncheckGroup) {
                this.getAllRadios().forEach(radio => {
                    radio.allowUncheck = true;
                });
            }
        }
    }
    handleDisabledChange() {
        this.getAllRadios().forEach(radio => {
            radio.disabled = this.disabled;
        });
    }
    handleInitialDisabledState() {
        this.getAllRadios().forEach(radio => {
            radio.disabled = radio.hasAttribute('disabled') ? radio.disabled : this.disabled;
        });
    }
    handleKeyDown(event) {
        if (this.disabled)
            return;
        if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(event.key)) {
            return;
        }
        const radios = this.getAllRadios().filter(radio => !radio.disabled);
        const checkedRadio = radios.find(radio => radio.checked) ?? radios[0];
        const incr = event.key === ' ' ? 0 : ['ArrowUp', 'ArrowLeft'].includes(event.key) ? -1 : 1;
        const oldValue = this.value;
        let index = radios.indexOf(checkedRadio) + incr;
        if (index < 0) {
            index = radios.length - 1;
        }
        if (index > radios.length - 1) {
            index = 0;
        }
        this.getAllRadios().forEach(radio => {
            radio.checked = false;
            if (!this.hasButtonGroup) {
                radio.tabIndex = -1;
            }
        });
        this.value = radios[index].value;
        radios[index].checked = true;
        if (!this.hasButtonGroup) {
            radios[index].tabIndex = 0;
            radios[index].focus();
        }
        else {
            radios[index].shadowRoot.querySelector('button').focus();
        }
        if (this.value !== oldValue) {
            this.emit('change');
            this.emit('input');
            this.emit(Nile_Events.NILE_CHANGE, { value: this.value });
            this.emit(Nile_Events.NILE_INPUT, { value: this.value });
        }
        event.preventDefault();
    }
    handleLabelClick() {
        if (this.disabled)
            return;
        const radios = this.getAllRadios();
        const checked = radios.find(radio => radio.checked);
        const radioToFocus = checked || radios[0];
        // Move focus to the checked radio (or the first one if none are checked) when clicking the label
        if (radioToFocus) {
            radioToFocus.focus();
        }
    }
    handleSlotChange() {
        const radios = this.getAllRadios();
        radios.forEach(radio => {
            radio.checked = radio.value === this.value;
            if (this.islabelborder) {
                radio.islabelborder = true;
            }
        });
        if (this.disabled) {
            radios.forEach(r => (r.tabIndex = -1));
            return;
        }
        const nile_radio_check = 'nile-radio-button';
        this.hasButtonGroup = radios.some(radio => radio.tagName.toLowerCase() === nile_radio_check);
        if (radios.length > 0 && !radios.some(radio => radio.checked)) {
            if (this.hasButtonGroup) {
                const buttonRadio = radios[0].shadowRoot.querySelector('button');
                buttonRadio.tabIndex = 0;
            }
            else {
                radios[0].tabIndex = 0;
            }
        }
        if (this.hasButtonGroup) {
            const buttonGroup = this.shadowRoot?.querySelector('nile-button-group');
        }
    }
    updateCheckedRadio() {
        const radios = this.getAllRadios();
        radios.forEach(radio => (radio.checked = radio.value === this.value));
    }
    handleValueChange() {
        if (this.hasUpdated) {
            this.updateCheckedRadio();
        }
    }
    render() {
        const hasLabelSlot = this.hasSlotController.test('label');
        const hasHelpTextSlot = this.hasSlotController.test('help-text');
        const hasLabelSuffixSlot = this.hasSlotController.test('label-suffix');
        const hasLabel = this.label ? true : !!hasLabelSlot;
        const hasHelpText = this.helpText ? true : false;
        const hasErrorMessage = this.errorMessage ? true : false;
        const defaultSlot = html `
      <slot
        @click=${this.handleRadioClick}
        @keydown=${this.handleKeyDown}
        @slotchange=${this.handleSlotChange}
        role="presentation"
      ></slot>
    `;
        return html `
      <fieldset
        part="form-control"
        class=${classMap({
            'form-control': true,
            'form-control--medium': true,
            'form-control--radio-group': true,
            'form-control--has-label': hasLabel,
            'form-control--has-help-text': hasHelpText
        })}
        role="radiogroup"
        aria-labelledby="label"
        aria-describedby="help-text"
        aria-errormessage="error-message"
      >
        <label
          part="form-control-label"
          id="label"
          class="form-control__label"
          aria-hidden=${hasLabel ? 'false' : 'true'}
          @click=${this.handleLabelClick}
        >
          <slot name="label">${this.label}</slot>
        </label>

        ${hasLabelSuffixSlot ? html ` <slot name="label-suffix"></slot> ` : ``}

        <div part="form-control-input" class="form-control-input">
          <div class="visually-hidden">
            <label class="radio-group__validation">
              <input
                type="text"
                class="radio-group__validation-input"
                ?required=${this.required}
                tabindex="-1"
                hidden
              />
            </label>
          </div>

          ${this.hasButtonGroup
            ? html `
            ${defaultSlot}
              `
            : html `
            <div part="options-base" class="${this.labelInline ? `form-control--inline-radio` : ``}"> ${defaultSlot}</div> `}
        </div>

        ${hasHelpText
            ? html `
                <nile-form-help-text>${this.helpText}</nile-form-help-text>
              `
            : ``}

        ${hasErrorMessage
            ? html `
                <nile-form-error-message
                  >${this.errorMessage}</nile-form-error-message
                >
              `
            : ``}

      </fieldset>
    `;
    }
};
NileRadioGroup.styles = styles;
__decorate([
    query('slot:not([name])')
], NileRadioGroup.prototype, "defaultSlot", void 0);
__decorate([
    state()
], NileRadioGroup.prototype, "hasButtonGroup", void 0);
__decorate([
    state()
], NileRadioGroup.prototype, "defaultValue", void 0);
__decorate([
    property()
], NileRadioGroup.prototype, "label", void 0);
__decorate([
    property()
], NileRadioGroup.prototype, "name", void 0);
__decorate([
    property({ reflect: true })
], NileRadioGroup.prototype, "value", void 0);
__decorate([
    property({ reflect: true })
], NileRadioGroup.prototype, "form", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileRadioGroup.prototype, "required", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileRadioGroup.prototype, "labelInline", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileRadioGroup.prototype, "disabled", void 0);
__decorate([
    property({ attribute: 'help-text', reflect: true })
], NileRadioGroup.prototype, "helpText", void 0);
__decorate([
    property({ attribute: 'error-message', reflect: true })
], NileRadioGroup.prototype, "errorMessage", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileRadioGroup.prototype, "islabelborder", void 0);
__decorate([
    property({ type: Boolean, reflect: true, attribute: true })
], NileRadioGroup.prototype, "allowUncheckGroup", void 0);
__decorate([
    watch('disabled', { waitUntilFirstUpdate: true })
], NileRadioGroup.prototype, "handleDisabledChange", null);
__decorate([
    watch('value')
], NileRadioGroup.prototype, "handleValueChange", null);
NileRadioGroup = __decorate([
    customElement('nile-radio-group')
], NileRadioGroup);
export { NileRadioGroup };
export default NileRadioGroup;
//# sourceMappingURL=nile-radio-group.js.map