import { inject, Injectable } from '@angular/core';
import { GenericService, Toaster } from '@iqser/common-ui';
import { ILicense, ILicenseFeature, ILicenseReport, ILicenseReportRequest, ILicenses } from '@red/domain';
import { BehaviorSubject, firstValueFrom, Observable, of } from 'rxjs';
import { catchError, filter } from 'rxjs/operators';
import dayjs from 'dayjs';
import { NGXLogger } from 'ngx-logger';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { LicenseFeatures } from '../modules/admin/screens/license/utils/constants';

const defaultOnError: ILicenses = {
    activeLicense: 'err',
    licenses: [
        {
            id: 'err',
            name: 'Error',
            product: 'Error',
            licensedTo: 'Error',
            licensedToEmail: 'Error',
            validFrom: '2023-01-01T00:00:00Z',
            validUntil: '2023-12-31T00:00:00Z',
            features: [
                {
                    name: LicenseFeatures.PROCESSING_PAGES,
                    type: 'NUMBER',
                    value: '2000000',
                },
                {
                    name: LicenseFeatures.PDFTRON,
                    type: 'STRING',
                    value:
                        'S25lY29uIEFHKGVuLmtuZWNvbi5zd2lzcyk6T0VNOkREQS1SOjpCKzpBTVMoMj' +
                        'AyMjEwMjkpOkZGQ0M0RDMzMDdEQUI0RjM4QjMxM0JDOUIyNDMzODJDNEU2RjZGQ0I4M0NEOEFDNTc0MzU4QTk1OTczMEI2MjJGQUJFRjVDNw==',
                },
            ],
        },
    ],
};

@Injectable({
    providedIn: 'root',
})
export class LicenseService extends GenericService<ILicenseReport> {
    readonly licenseData$: Observable<ILicenses>;
    readonly selectedLicense$: Observable<ILicense>;
    selectedLicenseReport: ILicenseReport = {};
    allLicensesReport: ILicenseReport = {};
    protected readonly _defaultModelPath = 'report';
    readonly #licenseData$ = new BehaviorSubject<ILicenses | undefined>(undefined);
    readonly #selectedLicense$ = new BehaviorSubject<ILicense | undefined>(undefined);
    readonly #logger = inject(NGXLogger);
    readonly #toaster = inject(Toaster);

    get selectedLicense() {
        return this.#selectedLicense$.value;
    }

    get activeLicense() {
        if (!this.#licenseData$.value) {
            return undefined;
        }

        const { licenses, activeLicense: activeLicenseId } = this.#licenseData$.value;
        return licenses.find(license => license.id === activeLicenseId);
    }

    get activeLicenseKey(): string {
        const activeLicense = this.activeLicense;
        if (!activeLicense) {
            return '';
        }

        return activeLicense.features.find(f => f.name === LicenseFeatures.PDFTRON).value as string;
    }

    get totalLicensedNumberOfPages(): number {
        const processingPagesFeature = this.getFeature(LicenseFeatures.PROCESSING_PAGES);
        return Number(processingPagesFeature?.value ?? '-1');
    }

    get analyzedPagesPercentageForSelectedLicensePercentage(): number {
        return this.totalLicensedNumberOfPages > 0
            ? (this.selectedLicenseReport.numberOfAnalyzedPages / this.totalLicensedNumberOfPages) * 100
            : -1;
    }

    get analysisCapacityBytes(): number {
        const capacityFeature = this.getFeature(LicenseFeatures.ANALYSIS_CAPACITY_BYTES);
        return (Number(capacityFeature?.value ?? '-1') / 10) * 10;
    }

    get retentionCapacityBytes(): number {
        const capacityFeature = this.getFeature(LicenseFeatures.RETENTION_CAPACITY_BYTES);
        return Number(capacityFeature?.value ?? '-1');
    }

    get analysisCapacityBytesForSelectedLicensePercentage(): number {
        return this.analysisCapacityBytes > 0 ? (this.selectedLicenseReport.analysedFilesBytes / this.analysisCapacityBytes) * 100 : -1;
    }

    get retentionCapacityBytesForSelectedLicensePercentage(): number {
        return this.retentionCapacityBytes > 0
            ? (this.selectedLicenseReport.totalFilesUploadedBytes / this.retentionCapacityBytes) * 100
            : -1;
    }

    get unlicensedPages(): number {
        return Math.max(0, this.selectedLicenseReport.numberOfAnalyzedPages - this.totalLicensedNumberOfPages);
    }

    get isPageBased(): boolean {
        return this.totalLicensedNumberOfPages >= 0;
    }

    get isCapacityBased(): boolean {
        return this.analysisCapacityBytes >= 0 && this.retentionCapacityBytes >= 0;
    }

    constructor() {
        super();
        this.selectedLicense$ = this.#selectedLicense$.pipe(filter(license => !!license));
        this.licenseData$ = this.#licenseData$.pipe(filter(licenses => !!licenses));
    }

    getFeature(name: string): ILicenseFeature | undefined {
        return this.selectedLicense.features?.find(f => f.name === name);
    }

    async loadLicenseData(license: ILicense = this.selectedLicense) {
        const startDate = dayjs(license.validFrom);
        const endDate = dayjs(license.validUntil);

        this.selectedLicenseReport = await this.getReport({
            startDate: startDate.toDate(),
            endDate: endDate.toDate(),
        });

        this.allLicensesReport = await this.getReport({
            startDate: '2020-01-01T00:00:00.000Z',
            endDate: '2023-12-31T00:00:00.000Z',
        });
    }

    setDefaultSelectedLicense() {
        this.setSelectedLicense(this.activeLicense);
    }

    getReport(body: ILicenseReportRequest) {
        return firstValueFrom(this._post(body, `${this._defaultModelPath}/license`));
    }

    async loadLicenses() {
        const licenses$ = this._http.get<ILicenses>(`/${this._serviceName}/license`).pipe(catchError(() => of(defaultOnError)));
        const licenses = await firstValueFrom(licenses$);
        this.#licenseData$.next(licenses);
        this.setDefaultSelectedLicense();
        const activeLicense = this.activeLicense;
        if (!activeLicense) {
            this.#logger.error('[LICENSE] No active license found!');
            this.#toaster.warning(_('no-active-license'));
        }
    }

    setSelectedLicense($event: ILicense) {
        this.#selectedLicense$.next($event);
    }
}
