import { KeyValue } from '@angular/common'
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
import moment from 'moment'
import { ValidateFilterSASResponse } from 'src/app/models/sas/validate-filter.model'
import { QueryClause } from 'src/app/models/TableData'
import { HelperService } from 'src/app/services/helper.service'
import { SasStoreService } from 'src/app/services/sas-store.service'
import { DcValidator } from 'src/app/shared/dc-validator/dc-validator'
import { DcValidation } from 'src/app/shared/dc-validator/models/dc-validation.model'
import {
  EditRecordDropdownChangeEvent,
  EditRecordInputFocusedEvent
} from '../../models/edit-record/edit-record-events'
import { EditRecordModal } from '../../models/EditRecordModal'

@Component({
  selector: 'app-edit-record',
  templateUrl: './edit-record.component.html',
  styleUrls: ['./edit-record.component.scss']
})
export class EditRecordComponent implements OnInit {
  @Input() currentRecord!: EditRecordModal
  @Input() recordAction: string | null = null
  @Input() libds: string | undefined
  @Input() queryFilter: any
  @Input() filter: boolean = false
  @Input() submitLoading: boolean = false
  @Input() headerPks: string[] = []
  @Input() cellValidation: DcValidation[] = []
  @Input() currentRecordIndex: number = -1
  @Input() currentRecordLoadings: number[] = []
  @Input() currentRecordErrors: number[] = []
  @Input() currentRecordValidator: DcValidator | undefined

  @Output() onRecordChange: EventEmitter<EditRecordModal> =
    new EventEmitter<EditRecordModal>()
  @Output() onRecordInputFocused: EventEmitter<EditRecordInputFocusedEvent> =
    new EventEmitter<EditRecordInputFocusedEvent>()
  @Output()
  onRecordDropdownChanged: EventEmitter<EditRecordDropdownChangeEvent> =
    new EventEmitter<EditRecordDropdownChangeEvent>()
  @Output() onRecordEditClose: EventEmitter<any> = new EventEmitter<any>()
  @Output() onRecordEditConfirm: EventEmitter<any> = new EventEmitter<any>()
  @Output() onNextRecord: EventEmitter<any> = new EventEmitter<any>()
  @Output() onPreviousRecord: EventEmitter<any> = new EventEmitter<any>()

  public currentRecordInvalidCols: string[] = []
  public generateEditRecordUrlLoading: boolean = false
  public generatedRecordUrl: string | null = null
  public addRecordUrl: string | null = null
  public recordNewOrPkModified: boolean = false
  public addRecordLoading: boolean = false
  public validatorTimeout: any

  constructor(
    private sasStoreService: SasStoreService,
    private helperService: HelperService
  ) {}

  ngOnInit(): void {}

  /**
   * Runs native HOT validator against cell value
   * @param cellValidation column rules
   * @param cellValue value in the cell that is beign validated
   * @returns Promise boolean - wether valid or invalid
   */
  async validateRecordCol(
    cellValidation: any,
    cellValue: any
  ): Promise<boolean> {
    return new Promise((resolve, reject) => {
      this.currentRecordValidator?.executeHotValidator(
        cellValidation,
        cellValue,
        (valid: boolean) => {
          resolve(valid)
        }
      )
    })
  }

  /**
   * Fired when date field in the record change
   * Function will parse date and format to string
   * @param date picker value
   * @param colKey column name (key)
   */
  recordDateChange(date: Date, colKey: string) {
    let cellValidation = this.currentRecordValidator?.getRule(colKey)
    let format = cellValidation ? cellValidation.dateFormat : ''

    if (this.currentRecord)
      this.currentRecord[colKey] = moment(date).format(format)
  }

  /**
   * Close edit record modal and apply changes by emitting output event
   */
  confirmRecordEdit() {
    if (this.currentRecordInvalidCols.length < 1) {
      this.onRecordChange.emit(this.currentRecord)
    }
  }

  /**
   * Close edit record modal without applying the changes
   */
  closeRecordEdit() {
    this.onRecordEditClose.emit()
  }

  /**
   * Emitting output event when dropdown (autocomplete) input in any col change
   * @param colName column name (key)
   * @param col column index
   */
  onRecordDropdownChange(colName: string, col: number) {
    this.onRecordDropdownChanged.emit({ colName, col })
  }

  /**
   * Emitting output event when input is focused (clicked on) so we can run a `dynamic cell validation`
   * Since that bit must be run from the parent component (editor.component)
   * Result is then applied in the `cellValidation` variable and automatically updated in this component.
   * @param event input event
   * @param colName column name (key)
   */
  onRecordInputFocus(event: any, colName: number) {
    this.onRecordInputFocused.emit({ event, colName })
  }

  recordInputPaste(event: any) {
    setTimeout(() => {
      //Trim space at the end
      event.target.value = event.target.value.replace(/\s+$/, '')
    }, 0)
  }

  async recordInputChange(event: any, colName: string) {
    const colRules = this.currentRecordValidator?.getRule(colName)
    const value = event.target.value

    this.helperService.debounceCall(300, () => {
      this.validateRecordCol(colRules, value).then((valid: boolean) => {
        const index = this.currentRecordInvalidCols.indexOf(colName)

        if (valid) {
          if (index > -1) this.currentRecordInvalidCols.splice(index, 1)
        } else {
          if (index < 0) this.currentRecordInvalidCols.push(colName)
        }
      })
    })
  }

  onNextRecordClick() {
    this.onNextRecord.emit()
  }

  onPreviousRecordClick() {
    this.onPreviousRecord.emit()
  }

  public copyToClip(text: string) {
    const modalElement = document.querySelector('#recordModalRef .modal-title')

    if (modalElement) {
      const selBox = document.createElement('textarea')
      selBox.style.position = 'fixed'
      selBox.style.left = '0'
      selBox.style.top = '0'
      selBox.style.opacity = '0'
      selBox.style.zIndex = '5000'
      selBox.value = text
      modalElement.appendChild(selBox)
      selBox.focus()
      selBox.select()
      document.execCommand('copy')
      modalElement.removeChild(selBox)
      this.generatedRecordUrl = text
    }
  }

  async generateEditRecordUrl() {
    if (this.generatedRecordUrl) {
      this.copyToClip(this.generatedRecordUrl)
    } else {
      this.generateEditRecordUrlLoading = true

      const filterQueryClauseTable: QueryClause[] = []

      this.headerPks.forEach((key: string) => {
        let type = 'C'
        let rawValue = ''
        for (let i = 0; i < this.cellValidation.length; i++) {
          const obj = this.cellValidation[i]
          if (obj.data === key) {
            if (
              obj.type === 'numeric' ||
              obj.type === 'date' ||
              obj.type === 'time'
            ) {
              type = 'N'
            }
            break
          }
        }

        if (type === 'C') {
          rawValue = `'${this.currentRecord[key]}'`
        } else {
          rawValue = this.currentRecord[key].toString()
        }

        filterQueryClauseTable.push({
          GROUP_LOGIC: 'AND',
          SUBGROUP_LOGIC: 'AND',
          SUBGROUP_ID: 0,
          VARIABLE_NM: key,
          OPERATOR_NM: '=',
          RAW_VALUE: rawValue
        })
      })

      if (filterQueryClauseTable.length > 0 && this.libds) {
        await this.sasStoreService
          .saveQuery(this.libds, filterQueryClauseTable)
          .then((res: ValidateFilterSASResponse) => {
            const id = res.result[0].FILTER_RK
            const table = res.result[0].FILTER_TABLE
            this.queryFilter = { id: id, table: table }

            //copy to clipboard
            const editLink =
              location.href.split('#')[0] +
              '#/editor/edit-record/' +
              this.queryFilter.table +
              '/' +
              this.queryFilter.id

            this.copyToClip(editLink)

            this.generateEditRecordUrlLoading = false
            this.filter = false
          })
          .catch((err: any) => {
            this.submitLoading = false
          })
      }
    }
  }

  isColPk(col: string) {
    return this.headerPks.indexOf(col) > -1
  }

  originalOrder = (
    a: KeyValue<string, string>,
    b: KeyValue<string, string>
  ): number => {
    return 0
  }

  trackByFn(index: number, item: any): number {
    return index
  }
}
