import { LitElement } from 'lit';
import { A11yState } from './accessibility/a11y.state.enum';
import { A11yProperty } from './accessibility/a11y.property.enum';
import { Role } from './accessibility/role.enum';

export default class NileElement extends LitElement {
  protected BUBBLES: boolean = true;
  protected COMPOSED: boolean = true;
  protected CANCELABLE: boolean = false;

  /** Emits a custom event with more convenient defaults. */
  emit(name: string, detail?: any, bubbles?: boolean , composed?: boolean, cancelable?: boolean) {
    const event = new CustomEvent(
      name, 
      {
        bubbles: bubbles ?? this.BUBBLES,
        cancelable: cancelable ?? this.CANCELABLE,
        composed: composed ?? this.COMPOSED,
        detail
      }
    );

    this.dispatchEvent(event);
    return event;
  }
}


export interface NileFormControl extends NileElement {
  // Form attributes
  name: string;
  value: unknown;
  disabled?: boolean;
  defaultValue?: unknown;
  defaultChecked?: boolean;
  form?: string;

  // Constraint validation attributes
  pattern?: string;
  min?: number | string | Date;
  max?: number | string | Date;
  step?: number | 'any';
  required?: boolean;
  minlength?: number;
  maxlength?: number;

  // Form validation properties
  readonly validity: ValidityState;
  readonly validationMessage: string;

  // Form validation methods
  checkValidity: () => boolean;
  getForm: () => HTMLFormElement | null;
  reportValidity: () => boolean;
  setCustomValidity: (message: string) => void;
}

export interface A11yMetadataOptions {
  [Role.Role]?: string;

  [A11yState.AriaDisabled]?: boolean;
  [A11yState.AriaChecked]?: boolean;
  [A11yState.AriaSelected]?: boolean;
  [A11yState.AriaExpanded]?: boolean;
  [A11yState.AriaInvalid]?: boolean;
  [A11yState.AriaHidden]?: boolean;
  [A11yState.AriaPressed]?: boolean;
  [A11yState.AriaCurrent]?: string | boolean;
  [A11yState.AriaBusy]?: boolean;
  [A11yState.AriaRequired]?: boolean;
  [A11yState.AriaReadonly]?: boolean;
  [A11yState.AriaValueNow]?: string;
  [A11yState.AriaValueMin]?: string;
  [A11yState.AriaValueMax]?: string;
  [A11yState.AriaSort]?: string;

  [A11yProperty.AriaLabel]?: string;
  [A11yProperty.AriaLabelledby]?: string;
  [A11yProperty.AriaDescribedby]?: string;
  [A11yProperty.AriaErrormessage]?: string;
  [A11yProperty.AriaDetails]?: string;
  [A11yProperty.AriaControls]?: string;
  [A11yProperty.AriaOwns]?: string;
  [A11yProperty.AriaFlowto]?: string;
  [A11yProperty.AriaRoledescription]?: string;
  [A11yProperty.AriaModal]?: string;
  [A11yProperty.AriaOrientation]?: string;
  [A11yProperty.AriaKeyshortcuts]?: string;
  [A11yProperty.AriaValuenow]?: string;
  [A11yProperty.AriaValuemin]?: string;
  [A11yProperty.AriaValuemax]?: string;
  [A11yProperty.AriaValuetext]?: string;
  [A11yProperty.AriaLevel]?: string;
  [A11yProperty.AriaPosinset]?: string;
  [A11yProperty.AriaSetsize]?: string;
  [A11yProperty.AriaColcount]?: string;
  [A11yProperty.AriaColindex]?: string;
  [A11yProperty.AriaColspan]?: string;
  [A11yProperty.AriaRowcount]?: string;
  [A11yProperty.AriaRowindex]?: string;
  [A11yProperty.AriaRowspan]?: string;
  [A11yProperty.AriaAutocomplete]?: string;
  [A11yProperty.AriaPlaceholder]?: string;
  [A11yProperty.AriaHasPopup]?: string;
  [A11yProperty.Tabindex]?: string;
  [A11yProperty.AriaMultiselectable]?: string;
}

export function setupA11yMetadata(el: HTMLElement, options: A11yMetadataOptions = {}) {
  const role = options[Role.Role];
  if (role && !el.hasAttribute(Role.Role)) {
    el.setAttribute(Role.Role, role);
  }

  const missingLabel = !el.hasAttribute(A11yProperty.AriaLabelledby) && !el.hasAttribute(A11yProperty.AriaLabel);
  if (missingLabel) {
    const fallbackLabel = options[A11yProperty.AriaLabel] ?? options[A11yProperty.AriaLabelledby] ?? (options[A11yProperty.AriaLabelledby] ? (el as any).value : null);
    if (fallbackLabel?.trim()) {
      el.setAttribute(A11yProperty.AriaLabel, fallbackLabel.trim());
    }
  }

  const disabled = options[A11yState.AriaDisabled];
  if (disabled === true) {
    el.setAttribute(A11yState.AriaDisabled, 'true');
  } else if (disabled === false) {
    el.removeAttribute(A11yState.AriaDisabled);
  }

  for (const property of Object.values(A11yProperty)) {
    const value = (options as any)[property];
    if (value !== undefined && !el.hasAttribute(property)) {
      el.setAttribute(property, String(value));
    }
  }

  for (const state of Object.values(A11yState)) {
    if (state === A11yState.AriaDisabled) continue;
    const value = (options as any)[state];
    if (value === undefined) continue;
    el.setAttribute(state, String(value));
  }
}

function getLabelFromSlots(el: HTMLElement): string | null {
  const slot = el.querySelector('[slot="label"]');
  return slot?.textContent?.trim() || null;
}

function getLabelFromText(el: HTMLElement): string | null {
  const text = el.textContent?.trim();
  return text || null;
}