import { Component, OnDestroy, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatOptionModule } from '@angular/material/core';
import { MatSelectModule } from '@angular/material/select';
import { Observable, Subscription } from 'rxjs';
import { map, startWith } from 'rxjs/operators';

import { AeronefByImat, CanopyModelBySize, DropZoneByOaci, Jump, JumpByModule } from '@models';
import { AeronefsService, CanopiesService, DropZonesService, JumpsService } from '@services';

@Component({
    selector: 'app-jump-edit-dialog',
    templateUrl: 'jump-edit.dialog.html',
    imports: [
        AsyncPipe,
        FormsModule,
        ReactiveFormsModule,
        MatAutocompleteModule,
        MatButtonModule,
        MatCheckboxModule,
        MatDatepickerModule,
        MatDialogModule,
        MatFormFieldModule,
        MatIconModule,
        MatInputModule,
        MatSelectModule,
        MatOptionModule,
    ],
})
export class JumpEditDialogComponent implements OnDestroy {
    dialogRef = inject<MatDialogRef<JumpEditDialogComponent>>(MatDialogRef);
    private fb = inject(FormBuilder);
    private _aeronefsService = inject(AeronefsService);
    private _canopiesService = inject(CanopiesService);
    private _dropZonesService = inject(DropZonesService);
    private _jumpsService = inject(JumpsService);
    jump = inject<Jump>(MAT_DIALOG_DATA);

    private _aeronefByImat: Subscription = new Subscription();
    private _canopyModelBySize: Subscription = new Subscription();
    private _dropZoneByOaci: Subscription = new Subscription();
    private _jumpByModule: Subscription = new Subscription();
    public tagField = new FormControl<string>('', { nonNullable: true });
    public jumpForm: FormGroup;
    public inputOptions: {
        aeronefs: Array<AeronefByImat>;
        canopies: Array<CanopyModelBySize>;
        dropzones: Array<DropZoneByOaci>;
        categories: Array<JumpByModule>;
    };
    public filteredOptions: {
        aeronefs: Observable<Array<AeronefByImat>>;
        imats: Observable<Array<AeronefByImat>>;
        canopies: Observable<Array<CanopyModelBySize>>;
        tailles: Observable<Array<CanopyModelBySize>>;
        dropzones: Observable<Array<DropZoneByOaci>>;
        oaci: Observable<Array<DropZoneByOaci>>;
        categories: Observable<Array<JumpByModule>>;
        modules: Observable<Array<JumpByModule>>;
    };

    constructor() {
        this.inputOptions = { aeronefs: [], canopies: [], dropzones: [], categories: [] };
        const controlsConfig = {
            slug: [this.jump.slug, Validators.required],
            date: [this.jump.date, Validators.required],
            numero: [this.jump.numero, Validators.required],
            lieu: [this.jump.lieu, Validators.required],
            oaci: this.jump.oaci,
            aeronef: [this.jump.aeronef, Validators.required],
            imat: this.jump.imat,
            hauteur: [this.jump.hauteur, Validators.required],
            deploiement: this.jump.deploiement,
            voile: this.jump.voile,
            taille: [this.jump.taille?.toString(), Validators.required],
            categorie: this.jump.categorie,
            module: this.jump.module,
            participants: [this.jump.participants, Validators.required],
            programme: this.jump.programme,
            accessoires: this.jump.accessoires,
            zone: this.jump.zone,
            dossier: this.jump.dossier,
            video: this.jump.video,
        };
        this.jumpForm = this.fb.group(controlsConfig);

        this.filteredOptions = {
            aeronefs: this.jumpForm.controls['aeronef'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const aeronef = typeof value === 'string' ? value : value?.aeronef;
                    return aeronef ? this._filterImat(aeronef as string) : this.inputOptions.aeronefs.slice();
                }),
            ),
            imats: this.jumpForm.controls['imat'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const imat = typeof value === 'string' ? value : value?.imat;
                    return imat ? this._filterImat(imat as string) : this.inputOptions.aeronefs.slice();
                }),
            ),
            canopies: this.jumpForm.controls['voile'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const voile = typeof value === 'string' ? value : value?.voile;
                    return voile ? this._filterTaille(voile as string) : this.inputOptions.canopies.slice();
                }),
            ),
            tailles: this.jumpForm.controls['taille'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const taille = typeof value === 'string' ? value : value?.taille.toString();
                    return taille ? this._filterTaille(taille as string) : this.inputOptions.canopies.slice();
                }),
            ),
            dropzones: this.jumpForm.controls['lieu'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const lieu = typeof value === 'string' ? value : value?.lieu;
                    return lieu ? this._filterOaci(lieu as string) : this.inputOptions.dropzones.slice();
                }),
            ),
            oaci: this.jumpForm.controls['oaci'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const oaci = typeof value === 'string' ? value : value?.oaci;
                    return oaci ? this._filterOaci(oaci as string) : this.inputOptions.dropzones.slice();
                }),
            ),
            categories: this.jumpForm.controls['categorie'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const category = typeof value === 'string' ? value : value?.categorie;
                    return category ? this._filterModule(category as string) : this.inputOptions.categories.slice();
                }),
            ),
            modules: this.jumpForm.controls['module'].valueChanges.pipe(
                startWith(''),
                map((value) => {
                    const module = typeof value === 'string' ? value : value?.module;
                    return module ? this._filterModule(module as string) : this.inputOptions.categories.slice();
                }),
            ),
        };
        this._loadAeronefByImat();
        this._loadCanopyModelBySize();
        this._loadDropZoneByOaci();
        this._loadJumpByModule();
    }

    ngOnDestroy() {
        this._aeronefByImat.unsubscribe();
        this._canopyModelBySize.unsubscribe();
        this._dropZoneByOaci.unsubscribe();
        this._jumpByModule.unsubscribe();
    }

    private _filterImat(imat: string): Array<AeronefByImat> {
        const filterValue = imat.toLowerCase();
        return this.inputOptions.aeronefs.filter(
            (option) =>
                option.aeronef.toLowerCase().includes(filterValue) || option.imat.toLowerCase().includes(filterValue),
        );
    }

    private _filterModule(module: string): Array<JumpByModule> {
        const filterValue = module.toLowerCase();
        return this.inputOptions.categories.filter(
            (option) =>
                option.categorie.toLowerCase().includes(filterValue) ||
                option.module.toLowerCase().includes(filterValue),
        );
    }

    private _filterOaci(oaci: string): Array<DropZoneByOaci> {
        const filterValue = oaci.toLowerCase();
        return this.inputOptions.dropzones.filter(
            (option) =>
                option.lieu.toLowerCase().includes(filterValue) || option.oaci.toLowerCase().includes(filterValue),
        );
    }

    private _filterTaille(taille: string): Array<CanopyModelBySize> {
        const filterValue = taille.toLowerCase();
        return this.inputOptions.canopies.filter(
            (option) =>
                option.voile.toLowerCase().includes(filterValue) || option.taille.toString().includes(filterValue),
        );
    }

    private _loadAeronefByImat(): void {
        const aeronefs$ = this._aeronefsService.getAllByImat();
        this._aeronefByImat = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
            this.inputOptions.aeronefs = aggregate;
        });
    }

    private _loadCanopyModelBySize(): void {
        const canopies$ = this._canopiesService.getAllBySizeByModel();
        this._canopyModelBySize = canopies$.subscribe((aggregate: Array<CanopyModelBySize>) => {
            this.inputOptions.canopies = aggregate;
        });
    }

    private _loadDropZoneByOaci(): void {
        const dropzones$ = this._dropZonesService.getAllByOaci();
        this._dropZoneByOaci = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
            this.inputOptions.dropzones = aggregate;
        });
    }

    private _loadJumpByModule(): void {
        const jumps$ = this._jumpsService.getAllByModule();
        this._jumpByModule = jumps$.subscribe((aggregate: Array<JumpByModule>) => {
            this.inputOptions.categories = aggregate;
        });
    }

    addSautant(): void {
        const tag = this.tagField.value;
        if (tag != null && tag.trim() !== '' && this.jump.sautants.indexOf(tag) < 0) {
            this.jump.sautants.push(tag);
        }
        const participants = this.jump.sautants.length + 1;
        this.jumpForm.controls['participants'].setValue(participants);
        this.tagField.reset('');
    }

    closeDialog(): void {
        // close the dialog without result
        this.dialogRef.close();
    }

    displayAeronefFn(aeronef: AeronefByImat): string {
        let res = '';
        if (aeronef) {
            if (typeof aeronef === 'string') {
                res = aeronef;
            } else {
                res = aeronef.aeronef ? aeronef.aeronef : '';
            }
        }
        return res;
    }

    displayImatFn(aeronef: AeronefByImat): string {
        let res = '';
        if (aeronef) {
            if (typeof aeronef === 'string') {
                res = aeronef;
            } else {
                res = aeronef.imat ? aeronef.imat : '';
            }
        }
        return res;
    }

    displayLieuFn(dropzone: DropZoneByOaci): string {
        let res = '';
        if (dropzone) {
            if (typeof dropzone === 'string') {
                res = dropzone;
            } else {
                res = dropzone.lieu ? dropzone.lieu : '';
            }
        }
        return res;
    }

    displayOaciFn(dropzone: DropZoneByOaci): string {
        let res = '';
        if (dropzone) {
            if (typeof dropzone === 'string') {
                res = dropzone;
            } else {
                res = dropzone.oaci ? dropzone.oaci : '';
            }
        }
        return res;
    }

    displayTailleFn(canopy: CanopyModelBySize): string {
        let res = '';
        if (canopy) {
            if (typeof canopy === 'string') {
                res = canopy;
            } else {
                res = canopy.taille ? canopy.taille.toString() : '';
            }
        }
        return res;
    }

    displayVoileFn(canopy: CanopyModelBySize): string {
        let res = '';
        if (canopy) {
            if (typeof canopy === 'string') {
                res = canopy;
            } else {
                res = canopy.voile ? canopy.voile : '';
            }
        }
        return res;
    }

    displayCategorieFn(jump: JumpByModule): string {
        let res = '';
        if (jump) {
            if (typeof jump === 'string') {
                res = jump;
            } else {
                res = jump.categorie ? jump.categorie : '';
            }
        }
        return res;
    }

    displayModuleFn(jump: JumpByModule): string {
        let res = '';
        if (jump) {
            if (typeof jump === 'string') {
                res = jump;
            } else {
                res = jump.module ? jump.module : '';
            }
        }
        return res;
    }

    getErrorMessage(name: string): string {
        if (this.jumpForm.controls[name].errors !== null) {
            return `Ce champ est requis.`;
        }
        return '';
    }

    onSelAeronef(aeronef: AeronefByImat) {
        if (aeronef && aeronef.aeronef) {
            this.jumpForm.controls['imat'].setValue(aeronef);
        }
    }

    onSelImat(aeronef: AeronefByImat) {
        if (aeronef && aeronef.imat) {
            this.jumpForm.controls['aeronef'].setValue(aeronef);
        }
    }

    onSelLieu(dropzone: DropZoneByOaci) {
        if (dropzone && dropzone.oaci) {
            this.jumpForm.controls['oaci'].setValue(dropzone);
        }
    }

    onSelOaci(dropzone: DropZoneByOaci) {
        if (dropzone && dropzone.lieu) {
            this.jumpForm.controls['lieu'].setValue(dropzone);
        }
    }

    onSelTaille(canopy: CanopyModelBySize) {
        if (canopy && canopy.voile) {
            this.jumpForm.controls['voile'].setValue(canopy);
        }
    }

    onSelVoile(canopy: CanopyModelBySize) {
        if (canopy && canopy.taille) {
            this.jumpForm.controls['taille'].setValue(canopy);
        }
    }

    onSelCategorie(jump: JumpByModule) {
        if (jump && jump.categorie) {
            this.jumpForm.controls['module'].setValue(jump);
        }
    }

    onSelModule(jump: JumpByModule) {
        if (jump && jump.module) {
            this.jumpForm.controls['categorie'].setValue(jump);
        }
    }

    removeSautant(index: string): void {
        this.jump.sautants = this.jump.sautants.filter((sautant) => sautant !== index);
        const participants = this.jump.sautants.length + 1;
        this.jumpForm.controls['participants'].setValue(participants);
    }

    submitForm(): void {
        // update the model
        this.updateJump(this.jumpForm.value);
        this.jump.lieu =
            typeof this.jumpForm.controls['lieu'].value === 'string'
                ? this.jumpForm.controls['lieu'].value
                : this.jumpForm.controls['lieu'].value.lieu;
        this.jump.oaci =
            typeof this.jumpForm.controls['oaci'].value === 'string'
                ? this.jumpForm.controls['oaci'].value
                : this.jumpForm.controls['oaci'].value.oaci;
        this.jump.aeronef =
            typeof this.jumpForm.controls['aeronef'].value === 'string'
                ? this.jumpForm.controls['aeronef'].value
                : this.jumpForm.controls['aeronef'].value.aeronef;
        this.jump.imat =
            typeof this.jumpForm.controls['imat'].value === 'string'
                ? this.jumpForm.controls['imat'].value
                : this.jumpForm.controls['imat'].value.imat;
        this.jump.voile =
            typeof this.jumpForm.controls['voile'].value === 'string'
                ? this.jumpForm.controls['voile'].value
                : this.jumpForm.controls['voile'].value.voile;
        this.jump.taille =
            typeof this.jumpForm.controls['taille'].value === 'string'
                ? this.jumpForm.controls['taille'].value
                : this.jumpForm.controls['taille'].value.taille;
        this.jump.categorie =
            typeof this.jumpForm.controls['categorie'].value === 'string'
                ? this.jumpForm.controls['categorie'].value
                : this.jumpForm.controls['categorie'].value.categorie;
        this.jump.module =
            typeof this.jumpForm.controls['module'].value === 'string'
                ? this.jumpForm.controls['module'].value
                : this.jumpForm.controls['module'].value.module;
        // close the dialog with result
        this.dialogRef.close(this.jump);
    }

    updateJump(values: NonNullable<unknown>): void {
        Object.assign(this.jump, values);
    }
}
