import { ChangeDetectionStrategy, Component, inject, Input, OnChanges, SimpleChanges } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { getConfig } from '@iqser/common-ui';
import { Debounce } from '@iqser/common-ui/lib/utils';
import { Dossier, IDossierRequest } from '@red/domain';
import { DossiersService } from '@services/dossiers/dossiers.service';
import { FilesService } from '@services/files/files.service';
import { PermissionsService } from '@services/permissions.service';
import { UserService } from '@users/user.service';
import { compareLists } from '@utils/functions';
import { firstValueFrom } from 'rxjs';
import { map } from 'rxjs/operators';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';

@Component({
    selector: 'redaction-edit-dossier-team',
    templateUrl: './edit-dossier-team.component.html',
    styleUrls: ['./edit-dossier-team.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EditDossierTeamComponent implements EditDossierSectionInterface, OnChanges {
    readonly #userService = inject(UserService);
    readonly #dossiersService = inject(DossiersService);
    readonly #permissionsService = inject(PermissionsService);
    readonly #filesService = inject(FilesService);
    form = this.#getForm();
    readonly #formValue$ = this.form.valueChanges;
    searchQuery = '';
    @Input() dossier: Dossier;
    membersSelectOptions: string[] = [];
    readonly ownersSelectOptions = this.#userService.all.filter(u => u.isManager).map(m => m.id);
    readonly selectedReviewers$ = this.#formValue$.pipe(map(v => v.members.filter(m => !v.approvers.includes(m))));
    readonly selectedApprovers$ = this.#formValue$.pipe(map(v => v.approvers));
    readonly isDocumine = getConfig().IS_DOCUMINE;

    get valid(): boolean {
        return this.form.valid;
    }

    get disabled() {
        return !this.#permissionsService.canEditTeamMembers() || !this.form.get('owner').value;
    }

    get hasOwner() {
        return !!this.dossier.ownerId;
    }

    get changed() {
        const { owner, members, approvers } = this.form.getRawValue();

        if (this.dossier.ownerId !== owner) {
            return true;
        }

        const initialMembers = [...this.dossier.memberIds].sort();
        const currentMembers = members.sort();

        const initialApprovers = [...this.dossier.approverIds].sort();
        const currentApprovers = approvers.sort();
        return compareLists(initialMembers, currentMembers) || compareLists(initialApprovers, currentApprovers);
    }

    async save(): EditDossierSaveResult {
        if (!this.hasOwner) {
            const ownerId: string = this.form.get('owner').value;
            if (!this.isApprover(ownerId)) {
                this.toggleApprover(ownerId);
            }
            this.#updateLists();
        }
        const { owner, members, approvers } = this.form.getRawValue();
        const dossier = {
            ...this.dossier,
            memberIds: members,
            approverIds: approvers,
            ownerId: owner,
        } as IDossierRequest;

        const updatedDossier = await firstValueFrom(this.#dossiersService.createOrUpdate(dossier));
        await firstValueFrom(this.#filesService.loadAll(updatedDossier.dossierId));
        return { success: !!updatedDossier };
    }

    isMemberSelected(userId: string): boolean {
        return this.form.value.members.includes(userId);
    }

    isApprover(userId: string): boolean {
        return this.form.value.approvers.includes(userId);
    }

    toggleApprover(userId: string) {
        const currentApprovers = this.form.value.approvers;
        const approversControl = this.form.controls.approvers;
        if (this.isApprover(userId)) {
            approversControl.patchValue(currentApprovers.filter(a => a !== userId));
        } else {
            approversControl.patchValue([...currentApprovers, userId]);
            if (!this.isMemberSelected(userId) && !this.isDocumine) {
                this.toggleSelected(userId);
            }
        }
        this.#updateLists();
    }

    toggleSelected(userId: string) {
        const { members, approvers } = this.form.value;
        const { members: membersControl, approvers: approversControl } = this.form.controls;
        if (this.isMemberSelected(userId)) {
            membersControl.patchValue(members.filter(m => m !== userId));
            if (this.isApprover(userId)) {
                approversControl.patchValue(approvers.filter(a => a !== userId));
            }
        } else {
            membersControl.patchValue([...members, userId]);
        }
        this.#updateLists();
    }

    ngOnChanges(changes: SimpleChanges): void {
        if (changes.dossier.isFirstChange()) {
            setTimeout(() => this.#resetForm());
        }
    }

    revert() {
        this.#resetForm();
    }

    setMembersSelectOptions(value = this.searchQuery): void {
        const possibleMembers = this.#userService.all.filter(user => user.isUser || user.isManager);
        this.membersSelectOptions = possibleMembers
            .filter(user => this.#userService.getName(user.id).toLowerCase().includes(value.toLowerCase()))
            .filter(user => this.form.getRawValue().owner !== user.id)
            .map(user => user.id)
            .sort((a, b) => this.#userService.getName(a).localeCompare(this.#userService.getName(b)));
    }

    @Debounce(0)
    onChangeOwner(ownerId: string) {
        if (this.hasOwner) {
            if (!this.isApprover(ownerId)) {
                this.toggleApprover(ownerId);
            }
            // If it is an approver, it is already a member, no need to check
            this.#updateLists();
        }
    }

    #updateLists() {
        this.setMembersSelectOptions();
    }

    #sortByName(ids: string[]) {
        return ids.sort((a, b) => this.#userService.getName(a).localeCompare(this.#userService.getName(b)));
    }

    #getForm() {
        return new FormGroup({
            owner: new FormControl({ value: '', disabled: false }, Validators.required),
            approvers: new FormControl([]),
            members: new FormControl([]),
        });
    }

    #resetForm() {
        this.form.reset(
            {
                owner: { value: this.dossier.ownerId, disabled: !this.#permissionsService.canEditTeamMembers() },
                approvers: this.#sortByName([...this.dossier.approverIds]),
                members: this.#sortByName([...this.dossier.memberIds]),
            } as unknown,
            { emitEvent: true },
        );
        this.#updateLists();
    }
}
