/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import {Component, OnInit, ViewChild} from '@angular/core';
import {TokenManagementService} from './token.management.service';
import {KnoxToken} from './knox.token';
import {MatTableDataSource} from '@angular/material/table';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
import {MatSlideToggleChange} from '@angular/material/slide-toggle';
import {SelectionModel} from '@angular/cdk/collections';

@Component({
    selector: 'app-token-management',
    templateUrl: './token.management.component.html',
    styleUrls: ['../assets/token-management-ui.css'],
    providers: [TokenManagementService]
})

export class TokenManagementComponent implements OnInit {

    pathParts = window.location.pathname.split('/');
    topologyContext = '/' + this.pathParts[1] + '/' + this.pathParts[2] + '/';
    tokenGenerationPageURL = this.topologyContext + 'token-generation/index.html';

    userName: string;
    canSeeAllTokens: boolean;
    currentKnoxSsoCookieTokenId: string;
    knoxTokens: MatTableDataSource<KnoxToken> = new MatTableDataSource();
    selection = new SelectionModel<KnoxToken>(true, []);
    allKnoxTokens: KnoxToken[];

    displayedColumns = ['select', 'tokenId', 'issued', 'expires', 'userName', 'impersonated', 'knoxSso', 'comment', 'metadata', 'actions'];
    @ViewChild('knoxTokensPaginator') paginator: MatPaginator;
    @ViewChild('knoxTokensSort') sort: MatSort = new MatSort();

    showDisabledKnoxSsoCookies: boolean;
    showMyTokensOnly: boolean;

    showDisableSelectedTokensButton: boolean;
    showEnableSelectedTokensButton: boolean;
    showRevokeSelectedTokensButton: boolean;

    constructor(private tokenManagementService: TokenManagementService) {
        this.showDisabledKnoxSsoCookies = true;
        let isMatch: (record: KnoxToken, filter: String) => boolean = (record, filter) => {
          let normalizedFilter = filter.trim().toLocaleLowerCase();
          let matchesTokenId = record.tokenId.toLocaleLowerCase().includes(normalizedFilter);
          let matchesComment = record.metadata.comment && record.metadata.comment.toLocaleLowerCase().includes(normalizedFilter);
          let matchesUserName = record.metadata.userName.toLocaleLowerCase().includes(normalizedFilter);
          let matchesCreatedBy = record.metadata.createdBy && record.metadata.createdBy.toLocaleLowerCase().includes(normalizedFilter);
          let matchesCustomMetadata = false;
          if (record.metadata.customMetadataMap) {
            for (let entry of Array.from(Object.entries(record.metadata.customMetadataMap))) {
	          if (entry[0].toLocaleLowerCase().includes(normalizedFilter) || entry[1].toLocaleLowerCase().includes(normalizedFilter)) {
                  matchesCustomMetadata = true;
                  break;
              }
            }
          } else {
            matchesCustomMetadata = true; // nothing to match
          }

          return matchesTokenId || matchesComment || matchesCustomMetadata || matchesUserName || matchesCreatedBy;
        };

        this.knoxTokens.filterPredicate = function (record, filter) {
	      return isMatch(record, filter);
        };

        this.knoxTokens.sortingDataAccessor = (item, property) => {
           switch(property) {
             case 'metadata.comment': return item.metadata.comment;
             case 'metadata.username': return item.metadata.userName;
             case 'metadata.createdBy': return item.metadata.createdBy;
             default: return item[property];
           }
        };
    }

    onChangeShowDisabledCookies(value: MatSlideToggleChange) {
        this.showDisabledKnoxSsoCookies = value.checked;
        this.actualizeTokensToDisplay();
    }

    onChangeShowMyTokensOnly(value: MatSlideToggleChange) {
        this.showMyTokensOnly = value.checked;
        this.actualizeTokensToDisplay();
    }

    ngOnInit(): void {
        console.debug('TokenManagementComponent --> ngOnInit()');
        this.tokenManagementService.getSessionInformation()
            .then(sessionInformation => {
              this.canSeeAllTokens = sessionInformation.canSeeAllTokens;
              this.currentKnoxSsoCookieTokenId = sessionInformation.currentKnoxSsoCookieTokenId;
              this.setUserName(sessionInformation.user);
            });
    }

    setUserName(userName: string) {
        this.userName = userName;
        this.fetchKnoxTokens();
    }

    userCanSeeAllTokens(): boolean {
        return this.canSeeAllTokens;
    }

    fetchKnoxTokens(): void {
        this.tokenManagementService.getKnoxTokens(this.userName, this.canSeeAllTokens)
            .then(tokens => this.updateTokens(tokens));
    }

    private isMyToken(token: KnoxToken): boolean {
	    return token.metadata.userName === this.userName || (token.metadata.createdBy && token.metadata.createdBy === this.userName);
    }

    private isDisabledKnoxSsoCookie(token: KnoxToken): boolean {
        return token.metadata.knoxSsoCookie && !token.metadata.enabled;
    }

    private updateTokens(tokens: KnoxToken[]): void {
        this.allKnoxTokens = tokens;
        this.selection.clear();
        this.showHideBatchOperations();
        this.actualizeTokensToDisplay();
    }

    private actualizeTokensToDisplay(): void {
	    let tokensToDisplay = this.allKnoxTokens;

        if (!this.showDisabledKnoxSsoCookies) {
            tokensToDisplay = tokensToDisplay.filter(token => !this.isDisabledKnoxSsoCookie(token));
        }

        if (this.showMyTokensOnly) {
             tokensToDisplay = tokensToDisplay.filter(token => this.isMyToken(token));
         }

         this.knoxTokens.data = tokensToDisplay;

         setTimeout(() => {
            this.knoxTokens.paginator = this.paginator;
            this.knoxTokens.sort = this.sort;
         });
    }

    disableToken(tokenId: string) {
        this.tokenManagementService.setEnabledDisabledFlag(false, tokenId).then((response: string) => this.fetchKnoxTokens());
    }

    disableSelectedTokens(): void {
        this.tokenManagementService.setEnabledDisabledFlagsInBatch(false, this.getSelectedTokenIds())
            .then((response: string) => this.fetchKnoxTokens());
    }

    private getSelectedTokenIds(): string[] {
        let selectedTokenIds = [] as string[];
        this.selection.selected.forEach(token => selectedTokenIds.push(token.tokenId));
        return selectedTokenIds;
    }

    enableToken(tokenId: string) {
        this.tokenManagementService.setEnabledDisabledFlag(true, tokenId).then((response: string) => this.fetchKnoxTokens());
    }

    enableSelectedTokens(): void {
        this.tokenManagementService.setEnabledDisabledFlagsInBatch(true, this.getSelectedTokenIds())
            .then((response: string) => this.fetchKnoxTokens());
    }

    revokeToken(tokenId: string) {
        this.tokenManagementService.revokeToken(tokenId).then((response: string) => this.fetchKnoxTokens());
    }

    revokeSelectedTokens() {
        this.tokenManagementService.revokeTokensInBatch(this.getSelectedTokenIds()).then((response: string) => this.fetchKnoxTokens());
    }

    gotoTokenGenerationPage() {
        window.open(this.tokenGenerationPageURL, '_blank');
    }

    formatDateTime(dateTime: number) {
        return dateTime < 0 ? 'Never' : new Date(dateTime).toLocaleString();
    }

    isTokenExpired(expiration: number): boolean {
        return expiration < 0 ? false : Date.now() > expiration;
    }

    getExpirationColor(expiration: number): string {
        return this.isTokenExpired(expiration) ? 'red' : 'green';
    }

    getCustomMetadataArray(knoxToken: KnoxToken): [string, string][] {
      let mdMap = new Map();
      if (knoxToken.metadata.customMetadataMap) {
        mdMap = new Map(Object.entries(knoxToken.metadata.customMetadataMap));
      }

      return Array.from(mdMap);
    }

    isKnoxSsoCookie(knoxToken: KnoxToken): boolean {
      return knoxToken.metadata.knoxSsoCookie;
    }

    isDisabledKnoxSSoCookie(knoxToken: KnoxToken): boolean {
      return this.isKnoxSsoCookie(knoxToken) && !knoxToken.metadata.enabled;
    }

    applyFilter(filterValue: string) {
        filterValue = filterValue.trim(); // Remove whitespace
        filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
        this.knoxTokens.filter = filterValue;
    }

    /** Whether the number of selected elements matches the total number of rows. */
    isAllSelected(): boolean {
      const numSelected = this.selection.selected.length;
      const numRows = this.knoxTokens.filteredData.length;
      return numSelected === numRows;
    }

    /** Selects all rows if they are not all selected; otherwise clear selection. */
    masterToggle(): void {
        if (this.isAllSelected()) {
            this.selection.clear();
        } else {
            this.knoxTokens.filteredData.forEach(row => {
	            if (!this.isDisabledKnoxSsoCookie(row)) {
                    this.selection.select(row);
                }
            });
        }
        this.showHideBatchOperations();
    }

    onRowSelectionChange(knoxToken: KnoxToken): void {
        this.selection.toggle(knoxToken);
        this.showHideBatchOperations();
    }

    showHideBatchOperations() {
	    if (this.selection.isEmpty()) {
		    this.showDisableSelectedTokensButton = false;
            this.showEnableSelectedTokensButton = false;
            this.showRevokeSelectedTokensButton = false;
	    } else {
            this.showDisableSelectedTokensButton = this.selectionHasZeroExpiredToken(); // expired tokens must not be disabled
            this.showEnableSelectedTokensButton = this.selectionHasZeroExpiredToken();  // expired tokens must not be enabled
            this.showRevokeSelectedTokensButton = this.selectionHasZeroKnoxSsoCookie(); // KnoxSSO cookies must not be revoked
	    }
    }

    private selectionHasZeroKnoxSsoCookie(): boolean {
        return this.selection.selected.every(token => !token.metadata.knoxSsoCookie);
    }

    private selectionHasZeroExpiredToken(): boolean {
        return this.selection.selected.every(token => !this.isTokenExpired(token.expirationLong));
    }

    getFontWeight(token: KnoxToken): string {
        return this.isCurrentKnoxSsoCookietoken(token) ? 'bold' : 'normal';
    }

    private isCurrentKnoxSsoCookietoken(token: KnoxToken): boolean {
        return this.isKnoxSsoCookie(token) && token.tokenId === this.currentKnoxSsoCookieTokenId;
    }

}
