/*
 * 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';
import Swal from 'sweetalert2';

@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;
    tokenHashKeyPresent: boolean;
    knoxTokens: MatTableDataSource<KnoxToken> = new MatTableDataSource();
    selection = new SelectionModel<KnoxToken>(true, []);
    allKnoxTokens: KnoxToken[];

    displayedColumns = ['select', 'tokenId', 'issued', 'expires', 'userName', 'impersonated', 'type', '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.isTokenHashKeyPresent().then(
            tokenHashKeyPresent => {
                this.tokenHashKeyPresent = tokenHashKeyPresent;
                if (!tokenHashKeyPresent) {
                    this.showMissingKnoxTokenHashKeyPopup();
                }
            }
        );

        this.tokenManagementService.getSessionInformation()
            .then(sessionInformation => {
              this.canSeeAllTokens = sessionInformation.canSeeAllTokens;
              this.currentKnoxSsoCookieTokenId = sessionInformation.currentKnoxSsoCookieTokenId;
              this.setUserName(sessionInformation.user);
            });
    }

    isTokenHashKeyPresent(): boolean{
        return this.tokenHashKeyPresent;
    }

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

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

    fetchKnoxTokens(): void {
        if (this.tokenHashKeyPresent) {
            this.tokenManagementService.getKnoxTokens(this.userName, this.canSeeAllTokens)
                .then(tokens => this.updateTokens(tokens));
        } else {
            console.debug('knox.token.hash.key is missing, skipping Knox token fetch...');
        }
    }

    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 this.isKnoxSsoCookie(token) && !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 'KNOXSSO_COOKIE' === knoxToken.metadata.type;
    }

    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 => !this.isKnoxSsoCookie(token));
    }

    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;
    }

    private showMissingKnoxTokenHashKeyPopup(): void {
        const message = 'The required gateway-level alias, knox.token.hash.key, is missing.';
        Swal.fire({
            icon: 'warning',
            title: 'Token Management Disabled!',
            text: message,
            confirmButtonColor: '#7cd1f9'
        });
    }

}
