import { AsyncPipe, NgIf } from '@angular/common';
import { Component, inject } from '@angular/core';
import { AbstractControl, FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { CircleButtonComponent, getConfig, IconButtonComponent, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui';
import { List } from '@iqser/common-ui/lib/utils';
import { TranslateModule } from '@ngx-translate/core';
import { Dossier, DownloadFileType, DownloadFileTypes, File, IReportTemplate, WorkflowFileStatuses } from '@red/domain';
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
import { ReportTemplateService } from '@services/report-template.service';
import { SelectComponent } from '@shared/components/select/select.component';
import { downloadTypesForDownloadTranslations } from '@translations/download-types-translations';
import { ColorPickerModule } from 'ngx-color-picker';
import { NGXLogger } from 'ngx-logger';

export interface DownloadDialogData {
    readonly dossier: Dossier;
    readonly files: File[];
}

export interface DownloadDialogResult {
    downloadFileTypes: List<DownloadFileType>;
    reportTemplateIds: List;
    redactionPreviewColor: string;
}

@Component({
    templateUrl: './download-dialog.component.html',
    styleUrls: ['./download-dialog.component.scss'],
    standalone: true,
    imports: [
        NgIf,
        ReactiveFormsModule,
        SelectComponent,
        TranslateModule,
        ColorPickerModule,
        MatIconModule,
        IconButtonComponent,
        CircleButtonComponent,
        AsyncPipe,
    ],
})
export class DownloadDialogComponent extends IqserDialogComponent<DownloadDialogComponent, DownloadDialogData, DownloadDialogResult> {
    readonly #logger = inject(NGXLogger);
    readonly iconButtonTypes = IconButtonTypes;
    readonly hasApprovedFiles: boolean;
    readonly downloadTypes: { key: DownloadFileType; label: string }[];
    readonly availableReportTypes = this.#availableReportTypes;
    readonly form = this.#getForm();
    readonly isDocumine = getConfig().IS_DOCUMINE;
    initialFormValue = this.form.getRawValue();

    constructor(
        private readonly _defaultColorsService: DefaultColorsService,
        private readonly _reportTemplateController: ReportTemplateService,
        private readonly _formBuilder: FormBuilder,
    ) {
        super();
        this.hasApprovedFiles = this.data.files.some(file => file.workflowStatus === WorkflowFileStatuses.APPROVED);
        this.downloadTypes = this.#formDownloadTypes;
    }

    get reportTypesLength() {
        return this.form.controls.reportTemplateIds?.value?.length || 0;
    }

    get downloadFileTypesLength() {
        return this.form.controls.downloadFileTypes?.value?.length || 0;
    }

    get hasUnapprovedFiles() {
        return this.data.files.some(file => !file.isApproved);
    }

    get invalidDownload() {
        const downloadFileTypes = this.form.controls.downloadFileTypes.value;
        const onlyRedactedVersionSelected =
            downloadFileTypes.length && downloadFileTypes.every(type => type === DownloadFileTypes.REDACTED);

        return onlyRedactedVersionSelected && !this.hasApprovedFiles;
    }

    override get valid() {
        return this.form.valid && !this.invalidDownload;
    }

    get #availableReportTypes() {
        const dossierTemplateId = this.data.dossier.dossierTemplateId;
        const result = this._reportTemplateController.getAvailableReportTemplates(dossierTemplateId);
        return result.then(values => values ?? []);
    }

    get #formDownloadTypes() {
        return ['ORIGINAL', 'PREVIEW', 'DELTA_PREVIEW', 'REDACTED']
            .map((type: DownloadFileType) => ({
                key: type,
                label: downloadTypesForDownloadTranslations[type],
            }))
            .filter(type => {
                if (!this.hasApprovedFiles) {
                    return type.key !== DownloadFileTypes.REDACTED;
                }
                return true;
            });
    }

    get #selectedDownloadTypes(): List<DownloadFileType> {
        if (!this.data.dossier.downloadFileTypes) {
            return [];
        }
        return this.data.dossier.downloadFileTypes.filter(type => {
            if (!this.hasApprovedFiles) {
                return type !== DownloadFileTypes.REDACTED;
            }
            return true;
        });
    }

    override onEnterValidator() {
        return this.valid;
    }

    reportTemplateValueMapper = (reportTemplate: IReportTemplate) => reportTemplate.templateId;

    override close() {
        const result: DownloadDialogResult = {
            reportTemplateIds: this.form.controls.reportTemplateIds.value,
            downloadFileTypes: this.form.controls.downloadFileTypes.value,
            redactionPreviewColor: this.form.controls.redactionPreviewColor.value,
        };

        this.#logger.info('[DOWNLOAD] Closing with result', result);

        super.close(result);
    }

    #hasReportTemplateOrDownloadType(control: AbstractControl) {
        const atLeastAReportSelected = control.get('reportTemplateIds')?.value.length > 0;
        const atLeastATypeSelected = control.get('downloadFileTypes')?.value.length > 0;

        return atLeastATypeSelected || atLeastAReportSelected ? null : { reportTemplateIds: true, downloadFileTypes: true };
    }

    #getForm() {
        const previewColor = this._defaultColorsService.getColor(this.data.dossier.dossierTemplateId, 'previewColor');
        return this._formBuilder.group(
            {
                reportTemplateIds: [this.data.dossier.reportTemplateIds],
                downloadFileTypes: [this.#selectedDownloadTypes],
                redactionPreviewColor: [previewColor],
            },
            {
                validators: [control => this.#hasReportTemplateOrDownloadType(control), control => this.#isHexColor(control)],
            },
        );
    }

    #isHexColor(control: AbstractControl) {
        const color = control.get('redactionPreviewColor')?.value;
        const isHexColor = /^#[0-9A-F]{6}$/i.test(color);
        return isHexColor ? null : { redactionPreviewColor: true };
    }
}
