import { Location } from '@angular/common'
import { Component, OnInit, ViewEncapsulation } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ClrDatagridStringFilterInterface } from '@clr/angular'
import { Observable, of } from 'rxjs'
import { EventService } from '../services/event.service'
import { HelperService } from '../services/helper.service'
import { SasService } from '../services/sas.service'
import { globals } from '../_globals'

import { Injectable } from '@angular/core'
import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse'

interface MetaData {
  NAME: any
  TYPE: any
  VALUE: any
}
class NameFilter implements ClrDatagridStringFilterInterface<MetaData> {
  accepts(data: MetaData, search: string): boolean {
    return (
      '' + data.NAME === search || data.NAME.toLowerCase().indexOf(search) >= 0
    )
  }
}

class TypeFilter implements ClrDatagridStringFilterInterface<MetaData> {
  accepts(data: MetaData, search: string): boolean {
    return (
      '' + data.TYPE === search || data.TYPE.toLowerCase().indexOf(search) >= 0
    )
  }
}

class ValueFilter implements ClrDatagridStringFilterInterface<MetaData> {
  accepts(data: MetaData, search: string): boolean {
    return (
      '' + data.VALUE === search ||
      data.VALUE.toLowerCase().indexOf(search) >= 0
    )
  }
}

@Injectable({
  providedIn: 'root'
})
@Component({
  selector: 'app-metadata',
  templateUrl: './metadata.component.html',
  styleUrls: ['./metadata.component.scss'],
  host: {
    class: 'content-container'
  },
  encapsulation: ViewEncapsulation.None,
  standalone: false
})
export class MetadataComponent implements OnInit {
  metaDataList: Array<any> | undefined
  metaDataSearch: string = ''
  metaObjectList: Array<any> | undefined
  metaObjectShowList: Array<any> | undefined
  metaObjectSearch: string = ''
  metaObjectAssociations: Array<any> = []
  metaObjectAttributes: Array<any> = []
  assosiationNames: Array<any> | undefined
  assosiationProperties: Array<any> | undefined
  showTable: boolean = false
  showAcc: boolean = false
  root$: Observable<string[]> | undefined
  public metaDataId: string = ''
  public typeFilter: any
  public nameFilter: any
  public valueFilter: any
  public pageSize!: number
  public loading: boolean = true
  public metatypesLoading = true
  public metaObjectSize = 200
  public assoTypeSelected = ''
  public assoObjectSelected = ''
  public repositories: Array<any> | undefined
  public repository = ''
  public objectRoute = false
  public showData = false
  public objectView = false

  constructor(
    private eventService: EventService,
    private sasService: SasService,
    private helperService: HelperService,
    private location: Location,
    private router: Router,
    private route: ActivatedRoute
  ) {}

  ngOnInit() {
    globals.viewer.currentSelection = 'view/metadata'
    if (this.router.url.includes('/view/metadata/object/')) {
      this.objectRoute = true
      this.objectView = true
    }
    this.pageSize = 5

    // Initialize filters for accessibility
    this.typeFilter = new TypeFilter()
    this.nameFilter = new NameFilter()
    this.valueFilter = new ValueFilter()

    if (
      globals.metadata.metaDataList &&
      globals.metadata.metaRepositories &&
      !this.objectRoute
    ) {
      this.metaDataList = globals.metadata.metaDataList
      this.repositories = globals.metadata.metaRepositories
      this.repository = globals.metadata.selectedRepository
      this.loading = false
      this.metatypesLoading = false
      this.metaDataSearch = globals.metadata.metaDataSearch
    } else {
      this.sasService
        .request('metanav/metatypes', null)
        .then((res: RequestWrapperResponse) => {
          this.metaDataList = res.adapterResponse.types
          globals.metadata.metaDataList = this.metaDataList
          this.loading = false
          this.metatypesLoading = false
        })

      this.sasService
        .request('metanav/metarepos', null)
        .then((res: RequestWrapperResponse) => {
          let foundation = false
          this.repositories = []
          for (
            let index = 0;
            index < res.adapterResponse.outrepos.length;
            index++
          ) {
            this.repositories.push(res.adapterResponse.outrepos[index].NAME)
            if (res.adapterResponse.outrepos[index].NAME === 'Foundation') {
              foundation = true
            }
          }
          if (foundation) {
            this.repository = 'Foundation'
          } else {
            this.repository = res.adapterResponse.outrepos[0].NAME
          }
          globals.metadata.metaRepositories = this.repositories
          globals.metadata.selectedRepository = this.repository
          if (this.objectRoute) {
            this.eventService.closeSidebar()
            this.showData = true
            let name = ''
            let id = this.route.snapshot.params['objectID']
            // let temp = this.router.url.split("%20").join(" ").split("/").reverse();
            this.metaObjectList = []
            this.metaObjectList.push({ ID: id, NAME: name })
            this.metaObjectShowList = this.metaObjectList
            this.metaObjectOnClick(
              this.metaObjectShowList[0].ID,
              this.metaObjectShowList[0]
            )
          }
        })
    }
  }

  public treeNodeClicked(event: any, item: any, tree: any) {
    if (event.target.title === 'Collapse') {
      this.collapseTreeItems(tree, item)
    }
  }

  public collapseTreeItems(tree: any, itemToSkip: any) {
    tree.forEach((item: any) => {
      if (JSON.stringify(item) !== JSON.stringify(itemToSkip)) {
        item['expanded'] = false
      }
    })
  }

  public metaDataOnClick(metaDataId: string, metaData: any) {
    this.objectView = false
    this.location.replaceState('/view/metadata')
    this.showData = false
    this.loading = true
    this.selectmetaData(metaDataId, metaData)
  }

  public metaObjectOnClick(metaObjectId: string, metaObject: any) {
    this.assoObjectSelected = ' . '
    this.showAcc = false
    this.metaObjectAttributes = []
    this.selectmetaObject(metaObjectId, metaObject)
  }

  public async selectmetaData($event: any, metaData?: any) {
    const data: any = {
      SASControlTable: [{ metatype: $event, repo: this.repository }]
    }
    this.sasService
      .request('metanav/metaobjects', data)
      .then((res: RequestWrapperResponse) => {
        this.metaObjectList = res.adapterResponse.objects
        this.getMetaObjectAttributes(this.metaObjectSize)
        this.loading = false
        this.assoTypeSelected = $event
        this.eventService.closeSidebar()
        this.showData = true
      })
  }

  public async selectmetaObject($event: any, metaData?: any) {
    let data: any = {
      SASControlTable: [{ objecturi: $event }]
    }
    this.sasService
      .request('metanav/metadetails', data)
      .then((res: RequestWrapperResponse) => {
        this.metaObjectAssociations = res.adapterResponse.associations
        this.root$ = of(
          this.getAssosiationsCount(res.adapterResponse.associations)
        )
        this.showAcc = true
        this.showTable = true
        let metaObjectName = res.adapterResponse.attributes.find(
          (x: any) => x.NAME === 'Name'
        ).VALUE
        this.assoObjectSelected = metaObjectName
        metaData.NAME = metaObjectName
        let url = this.router.url
        if (this.objectRoute) {
          // this.location.replaceState(url.slice(0, url.lastIndexOf("object")) + "object/" + $event.slice(1 + $event.indexOf("\\")) + "/" + escape(metaData.NAME));
          this.location.replaceState(
            url.slice(0, url.lastIndexOf('object')) +
              'object/' +
              $event.slice(1 + $event.indexOf('\\'))
          )
        } else {
          // this.location.replaceState(url + "/object/" + $event.slice(1 + $event.indexOf("\\")) + "/" + escape(metaData.NAME));
          this.location.replaceState(
            url + '/object/' + $event.slice(1 + $event.indexOf('\\'))
          )
        }
        this.metaObjectAttributes = res.adapterResponse.attributes
      })
  }

  public async selectAssosiationsDetails($event: any, metaData?: any) {
    let data: any = {
      SASControlTable: [{ objecturi: $event }]
    }
    this.sasService
      .request('metanav/metadetails', data)
      .then((res: RequestWrapperResponse) => {
        this.metaObjectAttributes = res.adapterResponse.attributes
        this.showTable = true
      })
  }

  public getAssosiationsCount(assosiationList: Array<any>) {
    let assosiationsHash = new Map()
    for (let assosiation of assosiationList) {
      if (!assosiationsHash.has(assosiation.ASSOC)) {
        assosiationsHash.set(assosiation.ASSOC, {
          count: 0,
          details: []
        })
      }
      let assocObj: any = assosiationsHash.get(assosiation.ASSOC)
      assocObj.count++
      assocObj.details.push({
        ASSOCURI: assosiation.ASSOCURI,
        NAME: assosiation.NAME,
        display: assosiation.NAME,
        URI: assosiation.ASSOCURI.slice(assosiation.ASSOCURI.indexOf(':') + 1)
      })
    }
    let assocGrouped: Array<any> = []
    assosiationsHash.forEach(function (val: any, key) {
      assocGrouped.push({
        ASSOC: key,
        count: val.count,
        details: val.details,
        display: key + ' ( ' + val.count + ' )'
      })
    })
    return assocGrouped
  }

  public setTypeAssosiations(assosiationType: String) {
    let tempAssosiations: Array<any> = []
    for (let assosiation of this.metaObjectAssociations) {
      if (assosiation.ASSOC === assosiationType) {
        tempAssosiations.push(assosiation)
      }
    }
    this.assosiationNames = tempAssosiations
    return tempAssosiations
  }

  public assosiationNameOnClick(assosiationId: any) {
    this.assoObjectSelected = ' . '
    this.metaObjectAttributes = []
    this.showTable = false
    this.selectAssosiationsDetails(assosiationId)
  }

  public getChildren = (asso: any) => {
    // if group_association clicked return list of Objects
    if (asso.count) {
      return of(asso.details)
    }
    // else return following api response
    const data: any = {
      SASControlTable: [{ objecturi: asso.ASSOCURI }]
    }
    return this.sasService
      .request('metanav/metadetails', data)
      .then((res: RequestWrapperResponse) => {
        this.showTable = true
        this.metaObjectAttributes = res.adapterResponse.attributes
        this.assoObjectSelected = asso.NAME
        let url = this.router.url
        if (this.objectRoute) {
          // this.location.replaceState(url.slice(0, url.lastIndexOf("object")) + "object/" +asso.ASSOCURI.slice(1 + asso.ASSOCURI.indexOf("\\")) + "/" + escape(asso.NAME));
          this.location.replaceState(
            url.slice(0, url.lastIndexOf('object')) +
              'object/' +
              asso.ASSOCURI.slice(1 + asso.ASSOCURI.indexOf('\\'))
          )
        } else {
          // this.location.replaceState( url + "/object/" + asso.ASSOCURI.slice(1 + asso.ASSOCURI.indexOf("\\")) + "/" + escape(asso.NAME));
          this.location.replaceState(
            url +
              '/object/' +
              asso.ASSOCURI.slice(1 + asso.ASSOCURI.indexOf('\\'))
          )
        }
        return this.getAssosiationsCount(res.adapterResponse.associations)
      })
  }

  public metaListOnFilter() {
    this.helperService.libraryOnFilter(
      this.metaDataList,
      this.metaDataSearch,
      'ID'
    )

    globals.metadata.metaDataSearch = this.metaDataSearch
  }

  public metaObjectOnFilter() {
    this.metaObjectAttributes = []
    this.helperService.metaObjectOnFilter(
      this.metaObjectList,
      this.metaObjectSearch,
      'NAME'
    )
    this.getMetaObjectAttributes(this.metaObjectSize)
    globals.metadata.metaObjectSearch = this.metaObjectSearch
  }

  public getMetaObjectAttributes(num: number) {
    if (this.metaObjectList !== undefined && this.metaObjectList.length > num) {
      let counter = 0
      let breakIndex = -1
      for (let index = 0; index < this.metaObjectList.length; index++) {
        if (
          this.metaObjectList[index]['hidden'] === undefined ||
          this.metaObjectList[index]['hidden'] === false
        ) {
          counter++
        }
        if (counter === num) {
          breakIndex = index
          break
        }
      }
      if (breakIndex !== -1) {
        this.metaObjectShowList = this.metaObjectList.slice(0, breakIndex)
      } else {
        this.metaObjectShowList = this.metaObjectList
      }
    } else {
      this.metaObjectShowList = this.metaObjectList
    }
  }

  debounce: boolean = false
  panelChange(event: boolean, object: any) {
    if (!this.debounce) {
      this.metaObjectOnClick(object.ID, object)

      this.debounce = true

      setTimeout(() => {
        this.debounce = false
      }, 600)
    }
  }

  updateSelectedRepository() {
    globals.metadata.selectedRepository = this.repository
  }
}
