import { ActivatedRoute } from '@angular/router'
import { sanitiseForSas } from '../../shared/utils/sanitise'
import { SasStoreService } from '../../services/sas-store.service'
import {
  Component,
  AfterViewInit,
  OnDestroy,
  ViewEncapsulation
} from '@angular/core'
import { Subscription } from 'rxjs'
import { Router } from '@angular/router'
import { EventService } from '../../services/event.service'
import {
  AuditorsPostdataSASResponse,
  Param
} from '../../models/sas/auditors-postdata.model'
import { PublicGetChangeinfo } from 'src/app/models/sas/public-getchangeinfo.model'
import { SasService } from 'src/app/services'

interface ChangesObj {
  ind: any
  field: any
  prop: any
  original: any
}

@Component({
  selector: 'app-approve-details',
  templateUrl: './approve-details.component.html',
  styleUrls: ['./approve-details.component.scss'],
  host: {
    class: 'content-container'
  },
  encapsulation: ViewEncapsulation.None,
  standalone: false
})
export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
  private _detailsSub: Subscription | undefined
  public tableId: any
  public detailsOpen: any = false
  public rejectOpen: any = false
  public jsParams: any
  public keysArray!: Array<string>
  public submitArr!: Array<string>
  public hotSelection: any
  public lens: { new: number; updated: number; deleted: number } = {
    new: 0,
    updated: 0,
    deleted: 0
  }
  public loaded: boolean = false
  public loadingTable: boolean = false
  public submitReason: string = ''
  public instance: string = 'hotInstance'
  public params: Param | undefined
  public subObj: any
  public submitDetails: any
  public acceptLoading: boolean = false
  public rejectLoading: boolean = false
  public submitted: boolean = false
  public tableFlag: boolean = false
  public originals: any
  public rowKeys: any = []
  public rowHeader!: Array<any>
  public arrChanged!: Array<any>
  public arrOfChanges!: Array<any>
  public chArr: Array<any> = []
  public tableDetails: any
  public secondOpen: boolean = false
  public addCount: number | undefined
  public tableDescription: string | undefined
  public formattedValues: boolean = true
  private response: AuditorsPostdataSASResponse | undefined

  public changesArr: Array<ChangesObj> = []

  public diffTable: any = {
    data: []
  }

  public diffsLimit: boolean = false
  public recordsLimit: number = 100
  public refreshStartupserviceAfterApprove: boolean = false

  constructor(
    private sasStoreService: SasStoreService,
    private sasService: SasService,
    private eventService: EventService,
    private router: ActivatedRoute,
    private route: Router
  ) {}

  get noChanges() {
    return (
      this.lens.new === 0 && this.lens.updated === 0 && this.lens.deleted === 0
    )
  }

  public goToBase(base: any) {
    this.route.navigateByUrl('/view/data/' + base)
  }

  public goToApprovalsList() {
    this.route.navigateByUrl('/review/approve')
  }

  public getTable(tableId: any) {
    this.route.navigateByUrl('/stage/' + tableId)
  }

  public goBack(base: any) {
    this.route.navigateByUrl('/editor/' + base)
  }

  public goToViewer() {
    this.route.navigateByUrl('/view/data')
  }

  public showDetailsSelect($event: Event) {
    $event.preventDefault()
    this.tableFlag = !this.tableFlag
  }

  public getDetails() {
    this.detailsOpen = true
  }

  public onHotSelection(evt: any) {
    this.hotSelection = evt.slice(0, 4)
  }

  public onHotDeselect() {
    setTimeout(() => {
      this.hotSelection = null
    }, 100)
  }

  public async rejecting() {
    this.rejectLoading = true
    this.submitReason = sanitiseForSas(this.submitReason.replace(/\n/g, '. '))

    let rejParams = {
      STP_ACTION: 'REJECT_TABLE',
      TABLE: this.tableId,
      STP_REASON: this.submitReason
    }

    await this.sasStoreService
      .rejecting(rejParams, 'BrowserParams', 'approvers/rejection')
      .then((res: any) => {
        this.route.navigateByUrl('/review/history')
      })
      .catch((err: any) => {
        this.acceptLoading = false
        this.rejectLoading = false
      })
  }

  public async approveTable() {
    this.acceptLoading = true
    let approveParams = {
      ACTION: 'APPROVE_TABLE',
      TABLE: this.tableId,
      DIFFTIME: this.params?.DIFFTIME,
      LIBDS: this.params?.LIBDS
    }

    await this.sasStoreService
      .approveTable(approveParams, 'SASControlTable', 'auditors/postdata')
      .then((res: any) => {
        // If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables
        if (this.refreshStartupserviceAfterApprove)
          this.sasService.reloadStartupData()
        this.route.navigateByUrl('/review/history')
      })
      .catch((err: any) => {
        this.acceptLoading = false
      })
  }

  public goToSubmitList() {
    this.route.navigateByUrl('/review/submitted')
  }

  public async callChangesInfo(tableId: any) {
    await this.sasStoreService
      .getChangeInfo(tableId)
      .then((res: PublicGetChangeinfo) => {
        this.tableDetails = res.jsparams[0]
        this.jsParams = res.jsparams[0]

        let keysArray: Array<string> = []

        for (const key in this.jsParams) {
          if (this.jsParams.hasOwnProperty(key)) {
            keysArray.push(key)
          }
        }

        this.keysArray = keysArray

        // If we are approving MPE_TABLES we will arm the trigger for the reload of startup data to se the updated tables
        // After user approved if armed, reload will be triggered
        if (res.jsparams[0].BASE_DS === 'MPE_TABLES')
          this.refreshStartupserviceAfterApprove = true
      })
      .catch((err: any) => {
        this.acceptLoading = false
      })
      .finally(() => {
        this.loaded = true
      })
  }

  public formattingChanged() {
    this.calcDiff()
  }

  public calcDiff() {
    if (!this.response) return

    let news = this.response.new
    let updates = this.response.updates
    let deleted = this.response.deleted
    let originals = this.response.originals

    if (this.formattedValues) {
      news = this.response.fmt_new
      updates = this.response.fmt_updates
      deleted = this.response.fmt_deleted
      originals = this.response.fmt_originals
    }

    let delLen = deleted.length
    let upLen = updates.length
    let newLen = news.length
    this.originals = originals
    this.rowKeys = []

    for (let index = 0; index < updates.length; index++) {
      let keys = Object.keys(updates[index])
      for (let ind = 0; ind < keys.length; ind++) {
        if (updates[index][keys[ind]] !== originals[index][keys[ind]]) {
          this.changesArr.push({
            ind: index,
            field: keys[ind],
            prop: updates[index][keys[ind]],
            original: originals[index][keys[ind]]
          })
        }
      }
    }

    this.lens = {
      new: this.params?.NUM_ADDED || 0,
      updated: this.params?.NUM_UPDATED || 0,
      deleted: this.params?.NUM_DELETED || 0
    }

    let columns: Array<string> = []
    let all = updates.concat(news, deleted)

    for (let index = 0; index < this.response.cols.length; index++) {
      const element = this.response.cols[index].NAME
      columns.push(element)
    }

    // We need to limit lens in following calculation
    // since actual data returned is limited to 100 rows
    let added =
      this.lens.new > this.recordsLimit ? this.recordsLimit : this.lens.new
    let changed =
      this.lens.updated > this.recordsLimit
        ? this.recordsLimit
        : this.lens.updated
    let del =
      this.lens.deleted > this.recordsLimit
        ? this.recordsLimit
        : this.lens.deleted

    if (
      this.lens.new > this.recordsLimit ||
      this.lens.updated > this.recordsLimit ||
      this.lens.deleted > this.recordsLimit
    ) {
      this.diffsLimit = true
    } else {
      this.diffsLimit = false
    }

    this.addCount = added
    let chArr: Array<any> = []

    let cols: Array<any> = []
    for (let ind = 0; ind < columns.length; ind++) {
      const element = columns[ind]
      cols.push({
        data: element,
        readOnly: true
        // implement custom rendering
      })
    }
    this.diffTable.data = all
    for (let index = 0; index < all.length; index++) {
      const element = all[index]
      let rowKey = Object.keys(element)
      this.rowKeys.push(rowKey)
    }
    let arrChanged: Array<any> = []
    let arrOfChanges: Array<any> = []
    for (let index = 0; index < this.diffTable.data.length; index++) {
      if (index < changed && changed !== 0) {
        arrChanged.push([])
        arrOfChanges.push([])
        // if (index >= added && index < added + changed) {
        chArr.push('updated')
        let diffTableKeys = Object.keys(this.diffTable.data[index])
        for (let j = 0; j < diffTableKeys.length; j++) {
          let currColumn = diffTableKeys[j]
          if (originals[index][currColumn] !== updates[index][currColumn]) {
            arrChanged[index].push(true)
            arrOfChanges[index].push(originals[index][currColumn])
          } else {
            arrChanged[index].push(false)
            arrOfChanges[index].push(null)
          }
        }
        this.arrChanged = arrChanged
        this.arrOfChanges = arrOfChanges
      }
      if (index >= changed && index < changed + added) {
        chArr.push('added')
      }
      if (index > added + changed - 1) {
        chArr.push('deleted')
      }
    }
    this.chArr = chArr
    this.rowHeader = this.rowKeys[0]
    this.diffTable.data = all
  }

  async ngAfterViewInit() {
    // submitted page
    this._detailsSub = this.sasStoreService.submittDetail.subscribe(
      async (allData: any) => {
        this.subObj = allData.viewData
        this.tableId = allData.viewData.tableId

        this.submitted = allData.viewData.sub
        this.submitDetails = allData.data
        this.submitArr = []
        for (let item in this.submitDetails) {
          if (item !== 'sub') {
            this.submitArr.push(item)
          }
        }

        let diffs = {
          ACTION: 'SHOW_DIFFS',
          TABLE: this.tableId,
          DIFFTIME: new Date().toUTCString()
        }
        // show diffs and changes info in a same call
        this.sasStoreService
          .showDiffs(diffs, 'SASControlTable', 'auditors/postdata')
          .then((res: AuditorsPostdataSASResponse) => {
            let param = res.params[0]
            this.params = param
            this.response = res
            this.calcDiff()
            this.callChangesInfo(this.tableId)
          })
          .catch((err: any) => err)
          .finally(() => {
            this.loadingTable = true
          })
      }
    )
    if (typeof this.router.snapshot.params['tableId'] === 'undefined') {
      return
    } else {
      this.tableId = this.router.snapshot.params['tableId']
    }

    let params = {
      ACTION: 'SHOW_DIFFS',
      TABLE: this.tableId,
      DIFFTIME: new Date().toUTCString()
    }

    // show diffs call and changes info both
    this.sasStoreService
      .showDiffs(params, 'SASControlTable', 'auditors/postdata')
      .then((res: AuditorsPostdataSASResponse) => {
        let param = res.params[0]
        this.params = param
        this.response = res
        this.calcDiff()
        this.callChangesInfo(this.tableId)
      })
      .catch((err: any) => {
        this.acceptLoading = false
      })
      .finally(() => {
        this.loadingTable = true
        this.setFocus()
      })
  }

  ngOnDestroy() {
    if (this._detailsSub) {
      this._detailsSub.unsubscribe()
    }
  }

  private setFocus() {
    setTimeout(() => {
      let acceptBtn: any = window.document.getElementById('acceptBtn')
      if (!!acceptBtn) {
        acceptBtn.focus()
      }
    }, 200)
  }
}
