/**
 * Copyright Aquera Inc 2023
 *
 * This source code is licensed under the BSD-3-Clause license found in the
 * LICENSE file in the root directory of this source tree.
 */

import {  
  LitElement,
  html,
  CSSResultArray,
  TemplateResult,
} from 'lit';
import { customElement, query, property } from 'lit/decorators.js';
import { styles } from './nile-date-picker.css';
import NileElement from '../internal/nile-element';
import { NileDropdown } from '../nile-dropdown';

/**
 * Nile icon component.
 *
 * @tag nile-date-picker
 *
 */

import {
  parseDateFromFormat,
  formatDateToFormat,
  parseRangeFromFormat,
  normalizeDateRange
} from './nile-date-picker-utils';


@customElement('nile-date-picker')
export class NileDatePicker extends NileElement {
   /**
   * The styles for DatePicker
   * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]`
   */
  public static get styles(): CSSResultArray {
    return [styles];
  }

  @property({ type: Boolean }) range = false;

  @property({ type: Boolean }) hideTypes = false;

  @property({ type: Boolean, reflect: true }) doubleClickUnselect = false;

  @property({ type: Boolean, reflect: true }) allowClear = false;

  @property({ type: Boolean }) open = false;

  @property({ type: Boolean, attribute: 'hide-time-zone' }) hideTimeZone = false;

  @property({ type: String, reflect: true }) type: 'absolute' | 'relative' = 'absolute';

  @property({ type: Boolean, attribute: 'showManualInputs' }) 
  showManualInputs = false;

  @property() value: any;

  @property({ type: Array, attribute: 'hide-duration-fields' }) 
  hideDurationFields: any = [];

  @property({ attribute: 'allowedDates' }) allowedDates: any = '{}';

  @property({ type: Boolean, attribute: true, reflect: true }) syncDatePicker = false;

  @property({ type: String, attribute: true, reflect: true }) dateFormat = "DD/MM/YYYY";  

  @property({ type: String, attribute: true, reflect: true }) rangeSeparator = " - ";

  @property({ type: Number, attribute: true, reflect: true }) startYear: number;

  @property({ type: Number, attribute: true, reflect: true }) endYear: number;

  @property({ type: Boolean, attribute: true, reflect: true }) showYearDropdown = false;

  @property({ type: Boolean, attribute: true, reflect: true }) showMonthDropdown = false;

  @property({ type: Boolean, attribute: true, reflect: true }) portal = false;

  @property({ type: Boolean, attribute: true, reflect: true }) disabled = false;

  @query('nile-dropdown') dropdown: NileDropdown;

 /**
   * Render method
   * @slot This is a slot test
   */
  firstUpdated() {
    super.firstUpdated?.(new Map());

    if (!this.syncDatePicker) return;

    const input = this.querySelector("nile-input");
    if (!input) return;

    input.addEventListener("nile-input", (e: any) => {
      const text = e.detail.value;
      const { first, second } = parseRangeFromFormat(text, this.dateFormat, this.range, this.rangeSeparator);

      if (!this.range) {
        if (first) this.jumpTo(first);
        return;
      }

      if (first && !second) {
        this.jumpTo(first);
        this.syncRangeCalendar(first, null);
      }

      if (first && second) {
        const [start, end] = normalizeDateRange(first, second);
        if (end) this.jumpTo(end);
        this.syncRangeCalendar(start, end);
      }
    });
  }
  
  updated(changedProperties: Map<string, unknown>) {
    super.updated(changedProperties);
    if (changedProperties.has('disabled')) {
      this.updateTriggerDisabledState();
    }
  }
  

  private updateTriggerDisabledState() {
    const trigger = this.querySelector('[slot="trigger"]') as HTMLElement | null;
    if (!trigger) return;
    if ('disabled' in trigger) {
      (trigger as any).disabled = this.disabled;
    }
  }
  

  private jumpTo(date: Date) {
    this.open = true;
    const cal = this.shadowRoot!.querySelector("nile-calendar") as any;
    if (!cal) return;

    cal.currentYear = date.getFullYear();
    cal.currentMonth = date.getMonth();
    cal.value = date;
    cal.valueAttribute = date.toISOString();
  }


  private syncRangeCalendar(first: Date | null, second: Date | null) {
    const cal = this.shadowRoot!.querySelector("nile-calendar") as any;
    if (!cal) return;

    if (!this.range) return;

    if (first) cal.startDate = first;
    if (second) cal.endDate = second;
  }

  render(): TemplateResult {
    return html`
      <nile-dropdown ?disabled="${this.disabled}" .open="${this.open}" part="dd-base" .hoist="${true}" distance="6" exportparts="base" .portal="${this.portal}">
        <slot slot="trigger" part="trigger" name="trigger"></slot>  

        <nile-calendar
          .hideTypes="${this.hideTypes}"
          .type="${this.type}"
          value="${this.value}"
          .range="${this.range}"
          @nile-init="${(e:CustomEvent)=>e.stopPropagation()}"
          @nile-destroy="${(e:CustomEvent)=>e.stopPropagation()}"
          @nile-changed="${(e:CustomEvent)=>e.stopPropagation()}"

          @nile-change="${this.handleChanged}"

          .allowedDates="${this.allowedDates}"

          @nile-type-change="${(e:CustomEvent)=>{e.stopPropagation();this.emit('nile-type-change',e.detail)}}"
          @nile-clear="${(e:CustomEvent)=>{e.stopPropagation();this.emit('nile-clear')}}"
          .hideDurationFields="${this.hideDurationFields}"
          .showManualInputs="${this.showManualInputs}"
          .doubleClickUnselect="${this.doubleClickUnselect}"
          .allowClear="${this.allowClear}"
          .startYear="${this.startYear}"
          .endYear="${this.endYear}"
          ?showYearDropdown="${this.showYearDropdown}"
          ?showMonthDropdown="${this.showMonthDropdown}"
          .dateFormat="${this.dateFormat}"
        ></nile-calendar>
      </nile-dropdown>
    `;
  }


  handleChanged(event: CustomEvent) {
    event.stopPropagation();

    const detail = event.detail;
    const triggerInput = this.querySelector("nile-input");
    if (this.disabled) return;

    if (!this.range) {
      const picked = detail.value;

      if (picked && triggerInput) {
        triggerInput.value = formatDateToFormat(new Date(picked), this.dateFormat);
        triggerInput.emit("nile-input", { value: triggerInput.value });
      }

      this.emit('nile-changed', event.detail);
      this.emit('nile-change', event.detail);

      this.dropdown?.hide();
      return;
    }

    const start = detail.startDate;
    const end = detail.endDate;

    if (triggerInput) {
      let text = "";
      if (start) text += formatDateToFormat(new Date(start), this.dateFormat);
      if (start && end) text += " - " + formatDateToFormat(new Date(end), this.dateFormat);

      triggerInput.value = text;
      triggerInput.emit("nile-input", { value: text });
    }

    this.emit('nile-changed', event.detail);
    this.emit('nile-change', event.detail);

    if (this.dropdown) {
      this.dropdown.hide();
    }
  }

  connectedCallback() {
    super.connectedCallback();
    this.emit('nile-init');
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    this.emit('nile-destroy');
  }
}

export default NileDatePicker;

declare global {
  interface HTMLElementTagNameMap {
    'nile-date-picker': NileDatePicker;
  }
}
