import {
    Component,
    Input,
    OnInit,
    OnDestroy,
    ChangeDetectorRef,
} from '@angular/core';
import { Subscription , timer} from "rxjs";

import { clone, DEFAULT_SUPPORTED_MIME_TYPE, VULNERABILITY_SCAN_STATUS } from '../utils';
import {
    VulnerabilitySummary,
    TagService,
    ScanningResultService,
    Tag
} from '../service/index';
import { ErrorHandler } from '../error-handler/index';
import { ChannelService } from '../channel/index';
import { JobLogService } from "../service/index";

const STATE_CHECK_INTERVAL: number = 3000; // 3s
const RETRY_TIMES: number = 3;

@Component({
    selector: 'hbr-vulnerability-bar',
    templateUrl: './result-bar-chart-component.html',
    styleUrls: ['./scanning.scss']
})
export class ResultBarChartComponent implements OnInit, OnDestroy {
    @Input() repoName: string = "";
    @Input() tagId: string = "";
    @Input() summary: VulnerabilitySummary;
    onSubmitting: boolean = false;
    retryCounter: number = 0;
    stateCheckTimer: Subscription;
    scanSubscription: Subscription;
    timerHandler: any;

    constructor(
        private tagService: TagService,
        private scanningService: ScanningResultService,
        private errorHandler: ErrorHandler,
        private channel: ChannelService,
        private ref: ChangeDetectorRef,
        private jobLogService: JobLogService,
    ) { }

    ngOnInit(): void {
        if ((this.status === VULNERABILITY_SCAN_STATUS.RUNNING ||
            this.status === VULNERABILITY_SCAN_STATUS.PENDING) &&
            !this.stateCheckTimer) {
            // Avoid duplicated subscribing
            this.stateCheckTimer = timer(0, STATE_CHECK_INTERVAL).subscribe(() => {
                this.getSummary();
            });
        }
        this.scanSubscription = this.channel.scanCommand$.subscribe((tagId: string) => {
            let myFullTag: string = this.repoName + "/" + this.tagId;
            if (myFullTag === tagId) {
                this.scanNow();
            }
        });
    }

    ngOnDestroy(): void {
        if (this.stateCheckTimer) {
            this.stateCheckTimer.unsubscribe();
            this.stateCheckTimer = null;
        }
        if (this.scanSubscription) {
            this.scanSubscription.unsubscribe();
        }
    }

    // Get vulnerability scanning status
    public get status(): string {
        if (this.summary && this.summary.scan_status) {
            return this.summary.scan_status;
        }
        return VULNERABILITY_SCAN_STATUS.NOT_SCANNED;
    }

    public get completed(): boolean {
        return this.status === VULNERABILITY_SCAN_STATUS.SUCCESS;
    }

    public get error(): boolean {
        return this.status === VULNERABILITY_SCAN_STATUS.ERROR;
    }

    public get queued(): boolean {
        return this.status === VULNERABILITY_SCAN_STATUS.PENDING;
    }

    public get scanning(): boolean {
        return this.status === VULNERABILITY_SCAN_STATUS.RUNNING;
    }
    public get otherStatus(): boolean {
        return !(this.completed || this.error || this.queued || this.scanning);
    }

    scanNow(): void {
        if (this.onSubmitting) {
            // Avoid duplicated submitting
            console.log("duplicated submit");
            return;
        }

        if (!this.repoName || !this.tagId) {
            console.log("bad repository or tag");
            return;
        }

        this.onSubmitting = true;

        this.scanningService.startVulnerabilityScanning(this.repoName, this.tagId)
            .subscribe(() => {
                this.onSubmitting = false;

                // Forcely change status to queued after successful submitting
                this.summary = {
                    scan_status: VULNERABILITY_SCAN_STATUS.PENDING,
                };

                // Forcely refresh view
                this.forceRefreshView(1000);

                // Start check status util the job is done
                if (!this.stateCheckTimer) {
                    // Avoid duplicated subscribing
                    this.stateCheckTimer = timer(STATE_CHECK_INTERVAL, STATE_CHECK_INTERVAL).subscribe(() => {
                        this.getSummary();
                    });
                }
            }, error => {
                this.onSubmitting = false;
                this.errorHandler.error(error);
            });
    }

    getSummary(): void {
        if (!this.repoName || !this.tagId) {
            return;
        }

        this.tagService.getTag(this.repoName, this.tagId)
            .subscribe((t: Tag) => {
                // To keep the same summary reference, use value copy.
                if (t.scan_overview) {
                    this.copyValue(t.scan_overview[DEFAULT_SUPPORTED_MIME_TYPE]);
                }
                // Forcely refresh view
                this.forceRefreshView(1000);

                if (!this.queued && !this.scanning) {
                    // Scanning should be done
                    if (this.stateCheckTimer) {
                        this.stateCheckTimer.unsubscribe();
                        this.stateCheckTimer = null;
                    }
                }
                this.channel.tagDetail$.next(t);
            }, error => {
                this.errorHandler.error(error);
                this.retryCounter++;
                if (this.retryCounter >= RETRY_TIMES) {
                    // Stop timer
                    if (this.stateCheckTimer) {
                        this.stateCheckTimer.unsubscribe();
                        this.stateCheckTimer = null;
                    }
                    this.retryCounter = 0;
                }
            });
    }

    copyValue(newVal: VulnerabilitySummary): void {
        if (!this.summary || !newVal || !newVal.scan_status) { return; }
        this.summary = clone(newVal);
    }

    forceRefreshView(duration: number): void {
        // Reset timer
        if (this.timerHandler) {
            clearInterval(this.timerHandler);
        }
        this.timerHandler = setInterval(() => this.ref.markForCheck(), 100);
        setTimeout(() => {
            if (this.timerHandler) {
                clearInterval(this.timerHandler);
                this.timerHandler = null;
            }
        }, duration);
    }
    viewLog(): string {
        return  `/api/repositories/${this.repoName}/tags/${this.tagId}/scan/${this.summary.report_id}/log`;
    }
}
