import getSelector from '../../utilities/selector';
import { recordingControls } from './constants';
import { eventsToRecord, inputKeyCodes } from '../code-generator/constants';
import { findLastIndex } from 'lodash';
import { overlaySelectors } from '../overlay/constants';

export default class Recorder {
  constructor({ updateEventLog, eventLogs, events, store } = {}) {
    // this._boundedMessageListener = null
    this._eventLogs = eventLogs || [];
    this._previousEvent = null;
    this.store = store;

    this._isTopFrame = window.location === window.parent.location;
    this._isRecordingClicks = true;

    this.updateEventLog = updateEventLog || null;
    this.events = events || Object.values(eventsToRecord);

    this.boundedRecordEvent = this._recordEvent.bind(this);
  }

  init(cb) {
    this._addAllListeners();
    cb && cb();
    if (this._eventLogs.length == 0) {
      this._updateEventLogs({ control: recordingControls.EVENT_RECORDER_STARTED });
      this._updateEventLogs({
        control: recordingControls.GET_CURRENT_URL,
        action: 'GOTO',
        href: window.location.href,
      });
      this._updateEventLogs({
        control: recordingControls.GET_VIEWPORT_SIZE,
        coordinates: { width: window.innerWidth, height: window.innerHeight },
      });
    }
  }

  _addAllListeners() {
    this.events.forEach((type) => {
      window.addEventListener(type, this.boundedRecordEvent, true);
    });
  }

  _removeAllListeners() {
    // const events = Object.values(eventsToRecord);
    this.events.forEach((type) => window.removeEventListener(type, this.boundedRecordEvent, true));
  }

  _recordEvent(e) {
    try {
      const selector = e.type !== 'beforeunload' && e.type !== 'load' ? getSelector(e) : '';
      if (selector.includes('#' + 'custom-context-menu') || selector.includes('#' + overlaySelectors.OVERLAY_ID)) {
        return;
      }

      const initialEvent = {
        selector,
        value: e.target.value || undefined,
        tagName: e.target.tagName || undefined,
        action: e.type,
        keyCode: e.keyCode ? e.keyCode : undefined,
        key: e.key ? e.key : undefined,
        href: e.target.href ? e.target.href : window?.location?.href || undefined,
        coordinates: Recorder._getCoordinates(e),
      };

      if (this._previousEvent && this._previousEvent.timeStamp === e.timeStamp) {
        return;
      }

      if (e.type === eventsToRecord.INPUT && this._previousEvent?.type === 'input') {
        const lastInputLog = this._eventLogs.pop();
        this._updateEventLogs([
          ...this._eventLogs,
          {
            ...lastInputLog,
            value: e.target.value,
          },
        ]);
      }
      // // add field isExtractData if the event is triggered by clicking extract data
      // else if (e.type === eventsToRecord.CLICK && selector.includes('#extract-data')) {
      //   this._updateEventLogs({
      //     ...initialEvent,
      //     action: 'extract-data',
      //     selector: e?.target?.dataset?.selector,
      //     isTable: true,
      //     hasPagination: false,
      //     paginatedStart: '1',
      //     paginatedEnd: '1',
      //     isExtractData: true,
      //   });
      // } else if (e.type === eventsToRecord.CLICK && selector.includes('#pagination-selector')) {
      //   const lastExtractDataEventIndex = findLastIndex(this._eventLogs, (event) => event.action === 'extract-data');
      //   if (lastExtractDataEventIndex) {
      //     this._eventLogs[lastExtractDataEventIndex].paginationSelector = e?.target?.dataset?.selector;
      //     this._eventLogs[lastExtractDataEventIndex].isTable = true;
      //     this._eventLogs[lastExtractDataEventIndex].hasPagination = true;
      //   }
      //   if (this.updateEventLog) {
      //     this.updateEventLog((() => this._getEventLog())());
      //   }
      // } else if (e.type === eventsToRecord.CLICK && selector.includes('#next-page-selector')) {
      //   const lastExtractDataEventIndex = findLastIndex(this._eventLogs, (event) => event.action === 'extract-data');
      //   if (lastExtractDataEventIndex) {
      //     this._eventLogs[lastExtractDataEventIndex].nextPageSelector = e?.target?.dataset?.selector;
      //     this._eventLogs[lastExtractDataEventIndex].isTable = true;
      //     this._eventLogs[lastExtractDataEventIndex].hasPagination = true;
      //   }

      //   if (this.updateEventLog) {
      //     this.updateEventLog((() => this._getEventLog())());
      //   }
      // }
      else if (e.type === eventsToRecord.KEYDOWN) {
        console.log({ e });
        if (e.target.tagName !== 'INPUT') {
          this._updateEventLogs([
            ...this._eventLogs,
            {
              ...initialEvent,
              action: 'keydown',
              value: e.key,
            },
          ]);
        } else if (e.ctrlKey || e.metaKey) {
          if (e.key == 'a') {
            this._updateEventLogs([
              ...this._eventLogs,
              {
                ...initialEvent,
                action: 'select-all',
              },
            ]);
          } else if (e.key == 'c') {
            this._updateEventLogs([
              ...this._eventLogs,
              {
                ...initialEvent,
                action: 'copy',
              },
            ]);
          } else if (e.key == 'v') {
            this._updateEventLogs([
              ...this._eventLogs,
              {
                ...initialEvent,
                action: 'paste',
              },
            ]);
          }
        }
      } else {
        this._updateEventLogs([
          ...this._eventLogs,
          {
            ...initialEvent,
          },
        ]);
      }

      this._previousEvent = e;
    } catch (err) {
      console.error(err);
    }
  }

  _updateEventLogs(newEventLogs) {
    // filter messages based on enabled / disabled features
    if (
      newEventLogs?.length > 0 &&
      newEventLogs[newEventLogs.length - 1].action === 'click' &&
      !this._isRecordingClicks
    ) {
      return;
    }

    window.postMessage(newEventLogs, '*');
    this._eventLogs = newEventLogs;

    if (this.updateEventLog) {
      this.updateEventLog((() => this._getEventLogs())());
    }
    // await this.updateEventLog((() => this._eventLog)());
  }

  _getEventLogs() {
    return this._eventLogs?.map((event, index) => {
      return {
        ...event,
        id: `step_${index + 1}`,
      };
    });
  }

  _clearEventLog() {
    this._eventLogs = [];
  }

  disableClickRecording() {
    this._isRecordingClicks = false;
  }

  enableClickRecording() {
    this._isRecordingClicks = true;
  }

  static _getCoordinates(evt) {
    const eventsWithCoordinates = {
      mouseup: true,
      mousedown: true,
      mousemove: true,
      mouseover: true,
    };

    return eventsWithCoordinates[evt.type] ? { x: evt.clientX, y: evt.clientY } : null;
  }
}
