import { BaseStorage } from '../classes/base_storage.js';
import { MaterialIcon } from '../icons.js';
import { EventLocation } from '../calendar/event_location.js';
import { MelObject } from '../mel_object.js';
import { CalendarLoader } from '../calendar/calendar_loader.js';
import { DIV, P, BUTTON } from '../constants/constants_html.js';
import { EMPTY_STRING } from '../constants/constants.js';
import { FramesManager } from '../classes/frame_manager.js';

/**
 * Représente un évènement du calendrier.
 *
 * Liste des classes html pré-définie :
 * - melv2-event => Classe de l'élément
 * - melv2-event-date
 * - melv2-event-hour
 *   - melv2-event-hour-top
 *   - melv2-event-hour-bottom
 * - melv2-event-content
 *   - melv2-event-content-top
 *   - melv2-event-content-bottom
 * - melv2-event-separator
 * - melv2-event-side
 * - melv2-event-clickable
 * - melv2-event-button
 */
export class html_events extends mel_html2 {
  /**
   * Constructeur de la classe
   * @param {*} event Evènement qui sera utiliser pour génrer le html
   * @param {*} attribs Attributs de l'élément
   */
  constructor(event, attribs = {}, base_date = moment()) {
    super(CONST_HTML_DIV, { attribs });
    this._cache = new BaseStorage();
    const date =
      STRING === typeof event.start ? moment(event.start) : event.start;
    const end_date =
      STRING === typeof event.end ? moment(event.end) : event.end;
    Object.defineProperties(this, {
      event: {
        get: function () {
          return event;
        },
        configurable: true,
      },
      date: {
        get: function () {
          return moment(date);
        },
        configurable: true,
      },
      end_date: {
        get: function () {
          return end_date;
        },
        configurable: true,
      },
      base_date: {
        get: function () {
          return moment(base_date);
        },
        configurable: true,
      },
    });

    this.onaction = new MelEvent();
  }

  _before_generate() {
    this._create_content();

    if (!this.hasClass('melv2-event')) {
      this.addClass('melv2-event');
      this.onaction.add('events', () => {
        this._on_action_click();
      });
    }

    this.attribs['data-event-uid'] = this.event.uid;
  }

  _create_content() {
    const html_hour = new mel_html2(DIV, {
      attribs: { class: 'melv2-event-hour' },
      contents: this._create_range_hour(),
    });
    const html_infos = new mel_html2(DIV, {
      attribs: { class: 'melv2-event-content' },
      contents: this._create_event(),
    });
    const html_separator = new mel_html(DIV, {
      class: 'melv2-event-separator',
    });
    const html_side = new mel_html2(DIV, {
      attribs: { class: 'melv2-event-side' },
      contents: this._create_side_click(),
    });

    let html_date = new mel_html(
      DIV,
      { class: 'melv2-event-date' },
      this._date_format(),
    );

    if (this.attribs['data-ignore-date']) {
      html_date.css('display', 'none');
    }

    let html_clickable = new mel_html2(DIV, {
      attribs: { class: 'melv2-event-clickable' },
      contents: [html_date, html_hour, html_separator, html_infos],
    });
    html_clickable.onclick.push(() => {
      this.onaction.call();
    });
    html_clickable.onmouseover.push((event) => {
      $(event.currentTarget).parent().addClass('hovered');
    });
    html_clickable.onmouseout.push((event) => {
      $(event.currentTarget).parent().removeClass('hovered');
    });

    this._cache.clear();
    this.jcontents[0] = html_clickable;
    this.jcontents[1] = html_side;
    return this;
  }

  _create_range_hour() {
    const is_all_day = this.event.allDay;
    const top_content = is_all_day ? 'Journée' : this._hour_start();
    const bottom_content = is_all_day ? EMPTY_STRING : this._hour_end();
    const html_top_hour = new mel_html(
      P,
      { class: 'melv2-event-hour-top' },
      top_content,
    );
    const html_bottom_hour = new mel_html(
      P,
      { class: 'melv2-event-hour-bottom' },
      bottom_content,
    );

    return [html_top_hour, html_bottom_hour];
  }

  _create_event() {
    const top_content = this._get_title_formated();
    const bottom_content = this._get_description();
    const html_top = new mel_html(
      P,
      { class: 'melv2-event-content-top' },
      top_content,
    );
    const html_bottom = new mel_html(
      P,
      { class: 'melv2-event-content-bottom' },
      bottom_content,
    );

    return [html_top, html_bottom];
  }

  _create_side_click() {
    let htmls = [];
    const event = this.event;

    if (!this._cache.has('location'))
      this._cache.add('location', new EventLocation(event));

    /**
     * @type {EventLocation}
     */
    const locations = this._cache.get('location');
    if (locations.has()) {
      let html;
      let icon;
      for (const location of locations) {
        if (location.after_html_generation) {
          icon = location.icon;
          html = new mel_html2(BUTTON, {
            attribs: {
              class: `melv2-event-button ${mel_button.html_base_class_full}`,
            },
            contents: [new MaterialIcon(icon, null).get()],
          });
          html.onclick.push(location.side_action.bind(location));
          html = location.after_html_generation(html);
          htmls.push(html);
          html = null;
        }
      }
    }

    return htmls;
  }

  _get_title_formated() {
    const event = this.event;
    let title = mel_metapage.Functions.updateRichText(event.title);

    if (event.free_busy === 'free') title = `(libre)${title}`;
    else if (event.free_busy === 'telework') title = `(télétravail)${title}`;

    if (event.attendees !== undefined && event.attendees.length > 0) {
      const item = Enumerable.from(event.attendees)
        .where((x) => x.email === rcmail.env.mel_metapage_user_emails[0])
        .firstOrDefault(null);
      if (item !== null) {
        try {
          switch (item.status) {
            case 'NEEDS-ACTION':
              title += ' (En attente)';
              break;

            case 'ACCEPTED':
              title += ' (Accepté)';
              break;

            case 'TENTATIVE':
              title += ' (Peut-être)';
              break;

            case 'CANCELLED':
              title += ' (Annulé)';
              break;

            default:
              break;
          }
        } catch (error) {}
      }
    }

    return title;
  }

  _get_description() {
    let desc = EMPTY_STRING;
    const event = this.event;

    if (!this._cache.has('location'))
      this._cache.add('location', new EventLocation(event));

    /**
     * @type {EventLocation}
     */
    const location = this._cache.get('location');

    if (location.has()) {
      if (location.has_locations()) {
        desc = location.locations[0].location;

        if (location.locations.length > 1) desc += '...';
      } else {
        desc = [];
        if (location.has_audio()) desc.push(location.audio.desc);

        if (location.has_visio())
          desc.push(location.visio._get_description(location.locations.length));

        desc = desc.join(' & ');
      }
    }

    return desc;
  }

  _create_visio() {}

  _date_is({ day_to_add = 0 }) {
    return (
      this.date.startOf('day').format() ===
      moment().add(day_to_add, 'd').startOf('day').format()
    );
  }
  _is_today() {
    return CalendarLoader.Instance.is_date_okay(
      this.date,
      this.end_date,
      this.base_date,
    );
  }
  _is_tomorrow() {
    return this._date_is({ day_to_add: 1 });
  }

  _hour_function({ date, add_today = true }) {
    let hour = EMPTY_STRING;

    const now = this.base_date;
    const is_date_not_today =
      moment(date).startOf('day').format() !== now.startOf('day').format();

    const is_today = this._is_today();
    if (is_today && is_date_not_today) hour = date.format('DD/MM');
    else hour = date.format('HH:mm');

    return hour;
  }

  _hour_start() {
    return this._hour_function({
      date: this.date,
    });
  }

  _hour_end() {
    return this._hour_function({
      date: this.end_date,
      add_today: false,
    });
  }

  _date_format() {
    if (this._is_today()) return "Aujourd'hui";
    else if (this._is_tomorrow()) return 'Demain';
    else return this.date.format('DD/MM/YYYY');
  }

  /**
   * Ajoute un élément enfant
   * @param {mel_html} mel_html Elément à ajouter
   * @returns Chaînage
   */
  addContent(mel_html) {
    if (this.count() < 2) {
      this.jcontents[0] = null;
      this.jcontents[1] = null;
    }

    super.addContent(mel_html);
    return this;
  }

  async _on_action_click() {
    const date = this.date.toDate().getTime() / 1000.0;
    await html_events._action_click(this.event.calendar, date, this.event);
  }

  static async _action_click(source, date, event) {
    const FRAME = 'calendar';
    //const page_manager = MelObject.Empty();

    let args = {
      source,
      date,
    };
    // await page_manager.change_frame(FRAME, config);
    await FramesManager.Instance.switch_frame(FRAME, {
      args,
    });

    FramesManager.Instance.get_frame()[0].contentWindow.ui_cal.event_show_dialog(
      event,
    );
  }

  static $_toString($element) {
    return $element[0].outerHTML;
  }
}