// Copyright Project Harbor Authors
//
// Licensed 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 { ComponentFixture, TestBed } from '@angular/core/testing';
import { ResultBarChartComponent } from './result-bar-chart.component';
import { ResultTipHistogramComponent } from './result-tip-histogram/result-tip-histogram.component';
import { HistogramChartComponent } from './histogram-chart/histogram-chart.component';
import {
    JobLogDefaultService,
    JobLogService,
    ScanningResultDefaultService,
    ScanningResultService,
} from '../../../../../shared/services';
import { VULNERABILITY_SCAN_STATUS } from '../../../../../shared/units/utils';
import { NativeReportSummary } from '../../../../../../../ng-swagger-gen/models/native-report-summary';
import { SharedTestingModule } from '../../../../../shared/shared.module';
import { of, timer } from 'rxjs';
import { ArtifactService, ScanService } from 'ng-swagger-gen/services';

describe('ResultBarChartComponent (inline template)', () => {
    let component: ResultBarChartComponent;
    let fixture: ComponentFixture<ResultBarChartComponent>;
    const mockedSbomDigest =
        'sha256:052240e8190b7057439d2bee1dffb9b37c8800e5c1af349f667635ae1debf8f3';
    let mockData: NativeReportSummary = {
        report_id: '12345',
        scan_status: VULNERABILITY_SCAN_STATUS.SUCCESS,
        severity: 'High',
        end_time: new Date().toUTCString(),
        scanner: {
            name: 'Trivy',
            vendor: 'vm',
            version: 'v1.2',
        },
        summary: {
            total: 124,
            fixable: 50,
            summary: {
                High: 5,
                Low: 5,
            },
        },
    };
    let mockCloneData: NativeReportSummary = {
        report_id: '123456',
        scan_status: VULNERABILITY_SCAN_STATUS.SUCCESS,
        severity: 'High',
        end_time: new Date().toUTCString(),
        scanner: {
            name: 'Trivy',
            vendor: 'vm',
            version: 'v1.3',
        },
        summary: {
            total: 124,
            fixable: 50,
            summary: {
                High: 5,
                Low: 5,
            },
        },
    };

    const FakedScanService = {
        scanArtifact: () => of({}),
        stopScanArtifact: () => of({}),
    };
    const FakedArtifactService = {
        getArtifact: () =>
            of({
                accessories: null,
                addition_links: {
                    build_history: {
                        absolute: false,
                        href: '/api/v2.0/projects/xuel/repositories/ui%252Fserver%252Fconfig-dev/artifacts/sha256:052240e8190b7057439d2bee1dffb9b37c8800e5c1af349f667635ae1debf8f3/additions/build_history',
                    },
                    vulnerabilities: {
                        absolute: false,
                        href: '/api/v2.0/projects/xuel/repositories/ui%252Fserver%252Fconfig-dev/artifacts/sha256:052240e8190b7057439d2bee1dffb9b37c8800e5c1af349f667635ae1debf8f3/additions/vulnerabilities',
                    },
                },
                digest: 'sha256:052240e8190b7057439d2bee1dffb9b37c8800e5c1af349f667635ae1debf8f3',
                extra_attrs: {
                    architecture: 'amd64',
                    author: '',
                    config: {
                        Env: [
                            'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
                        ],
                        WorkingDir: '/',
                    },
                    created: '2024-01-10T10:05:33.2702206Z',
                    os: 'linux',
                },
                icon: 'sha256:0048162a053eef4d4ce3fe7518615bef084403614f8bca43b40ae2e762e11e06',
                id: 3,
                labels: null,
                manifest_media_type:
                    'application/vnd.docker.distribution.manifest.v2+json',
                media_type: 'application/vnd.docker.container.image.v1+json',
                project_id: 3,
                pull_time: '2024-04-02T01:50:58.332Z',
                push_time: '2024-03-06T09:47:08.163Z',
                references: null,
                repository_id: 2,
                scan_overview: {
                    duration: 2,
                    end_time: '2024-04-02T01:50:59.406Z',
                    scan_status: 'Success',
                    start_time: '2024-04-02T01:50:57.176Z',
                },
                size: 3957,
                tags: null,
                type: 'IMAGE',
            }),
    };
    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [SharedTestingModule],
            declarations: [
                ResultBarChartComponent,
                ResultTipHistogramComponent,
                HistogramChartComponent,
            ],
            providers: [
                {
                    provide: ScanningResultService,
                    useValue: ScanningResultDefaultService,
                },
                { provide: JobLogService, useValue: JobLogDefaultService },
                {
                    provide: ScanService,
                    useValue: FakedScanService,
                },
                {
                    provide: ArtifactService,
                    useValue: FakedArtifactService,
                },
            ],
        }).compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(ResultBarChartComponent);
        component = fixture.componentInstance;
        component.artifactDigest = 'mockTag';
        component.summary = mockData;
        component.repoName = 'mockRepo';
        component.artifactDigest = mockedSbomDigest;
        fixture.detectChanges();
    });

    it('should be created', () => {
        expect(component).toBeTruthy();
    });
    it('should show "scan stopped" if status is STOPPED', () => {
        component.summary.scan_status = VULNERABILITY_SCAN_STATUS.STOPPED;
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            fixture.detectChanges();
            let el: HTMLElement = fixture.nativeElement.querySelector('span');
            expect(el).toBeTruthy();
            expect(el.textContent).toEqual('VULNERABILITY.STATE.STOPPED');
        });
    });

    it('should show progress if status is SCANNING', () => {
        component.summary.scan_status = VULNERABILITY_SCAN_STATUS.RUNNING;
        fixture.detectChanges();

        fixture.whenStable().then(() => {
            fixture.detectChanges();

            let el: HTMLElement =
                fixture.nativeElement.querySelector('.progress');
            expect(el).toBeTruthy();
        });
    });

    it('should show QUEUED if status is QUEUED', () => {
        component.summary.scan_status = VULNERABILITY_SCAN_STATUS.PENDING;
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            fixture.detectChanges();

            let el: HTMLElement =
                fixture.nativeElement.querySelector('.bar-state');
            expect(el).toBeTruthy();
            let el2: HTMLElement = el.querySelector('span');
            expect(el2).toBeTruthy();
            expect(el2.textContent).toEqual('VULNERABILITY.STATE.QUEUED');
        });
    });

    it('should show summary bar chart if status is COMPLETED', () => {
        component.summary.scan_status = VULNERABILITY_SCAN_STATUS.SUCCESS;
        fixture.detectChanges();

        fixture.whenStable().then(() => {
            fixture.detectChanges();
            let el: HTMLElement = fixture.nativeElement.querySelector(
                'hbr-result-tip-histogram'
            );
            expect(el).not.toBeNull();
        });
    });
    it('Test ResultBarChartComponent getScanner', () => {
        fixture.detectChanges();
        component.summary = mockData;
        expect(component.getScanner()).toBe(mockData.scanner);
        component.projectName = 'test';
        component.repoName = 'ui';
        component.artifactDigest = 'dg';
        expect(component.viewLog()).toBe(
            '/api/v2.0/projects/test/repositories/ui/artifacts/dg/scan/12345/log'
        );
        component.copyValue(mockCloneData);
        expect(component.summary.report_id).toBe(mockCloneData.report_id);
    });
    it('Test ResultBarChartComponent status', () => {
        fixture.detectChanges();
        component.summary.scan_status = VULNERABILITY_SCAN_STATUS.SUCCESS;
        expect(component.status).toBe(VULNERABILITY_SCAN_STATUS.SUCCESS);
        expect(component.completed).toBeTruthy();
        expect(component.queued).toBeFalsy();
        expect(component.scanning).toBeFalsy();
        expect(component.stopped).toBeFalsy();
        expect(component.otherStatus).toBeFalsy();
        expect(component.error).toBeFalsy();
    });
    it('Test ResultBarChartComponent ngOnDestroy', () => {
        component.stateCheckTimer = timer(0, 10000).subscribe(() => {});
        component.ngOnDestroy();
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            expect(component.stateCheckTimer).toBeNull();
            expect(component.scanSubscription).toBeNull();
            expect(component.stopSubscription).toBeNull();
        });
    });
    it('Test ResultBarChartComponent scanNow', () => {
        fixture.detectChanges();
        component.scanNow();
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            fixture.detectChanges();
            expect(component.onSubmitting).toBeFalse();
        });
    });
    it('Test ResultBarChartComponent stopScan', () => {
        fixture.detectChanges();
        component.stopScan();
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            fixture.detectChanges();
            expect(component.onStopping).toBeFalse();
            expect(component.stateCheckTimer).toBeNull();
        });
    });
    it('Test ResultBarChartComponent getSummary', () => {
        fixture.detectChanges();
        component.getSummary();
        component.summary.scan_status = VULNERABILITY_SCAN_STATUS.SUCCESS;
        fixture.detectChanges();
        fixture.whenStable().then(() => {
            fixture.detectChanges();
            expect(component.summary.scan_status).toBe(
                VULNERABILITY_SCAN_STATUS.SUCCESS
            );
        });
    });
});
