import { Injectable, TemplateRef } from '@angular/core';
import { ButtonConfig, getConfig, TableColumnConfig } from '@iqser/common-ui';
import {
    annotationDefaultColorConfig,
    AnnotationShapeMap,
    Dossier,
    DossierTemplate,
    StatusSorter,
    User,
    WorkflowFileStatus,
} from '@red/domain';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { TranslateService } from '@ngx-translate/core';
import { UserPreferenceService } from '@users/user-preference.service';
import { UserService } from '@users/user.service';
import { workflowFileStatusTranslations } from '@translations/file-status-translations';
import {
    dossierMemberChecker,
    dossierMemberQuickChecker,
    dossierOwnerQuickChecker,
    dossierStateChecker,
    RedactionFilterSorter,
} from '../../utils';
import { workloadTranslations } from '@translations/workload-translations';
import { DossierStatsService } from '@services/dossiers/dossier-stats.service';
import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service';
import { PermissionsService } from '@services/permissions.service';
import { SharedDialogService } from '@shared/services/dialog.service';
import { DefaultColorsService } from '@services/entity-services/default-colors.service';
import { IFilterGroup, INestedFilter, keyChecker, NestedFilter } from '@iqser/common-ui/lib/filtering';

@Injectable()
export class ConfigService {
    readonly #isDocumine = getConfig().IS_DOCUMINE;
    constructor(
        private readonly _translateService: TranslateService,
        private readonly _userPreferenceService: UserPreferenceService,
        private readonly _userService: UserService,
        private readonly _dossierStatsService: DossierStatsService,
        private readonly _dossierStatesMapService: DossierStatesMapService,
        private readonly _dialogService: SharedDialogService,
        private readonly _permissionsService: PermissionsService,
        private readonly _defaultColorsService: DefaultColorsService,
    ) {}

    get tableConfig(): TableColumnConfig<Dossier>[] {
        const columns: TableColumnConfig<Dossier>[] = [
            { label: _('dossier-listing.table-col-names.name'), sortByKey: 'searchKey', width: '2fr' },
            { label: _('dossier-listing.table-col-names.last-modified'), sortByKey: 'changedDate' },
            { label: _('dossier-listing.table-col-names.owner'), class: 'user-column' },
            { label: _('dossier-listing.table-col-names.documents-status'), class: 'flex-end', width: 'auto' },
            { label: _('dossier-listing.table-col-names.dossier-state'), class: 'flex-end' },
        ];
        if (!this.#isDocumine) {
            columns.splice(2, 0, { label: _('dossier-listing.table-col-names.needs-work') });
        }
        return columns;
    }

    get _currentUser(): User {
        return this._userService.currentUser;
    }

    buttonsConfig(dossierTemplate: DossierTemplate): ButtonConfig[] {
        return [
            {
                label: _('dossier-listing.add-new'),
                action: () => this._openAddDossierDialog(dossierTemplate.id),
                hide: !this._permissionsService.canCreateDossier(dossierTemplate),
                icon: 'iqser:plus',
                type: 'primary',
                helpModeKey: 'new_dossier',
            },
        ];
    }

    filterGroups(entities: Dossier[], needsWorkFilterTemplate: TemplateRef<unknown>, dossierTemplateId: string) {
        const allDistinctFileStatus = new Set<string>();
        const allDistinctPeople = new Set<string>();
        const allDistinctNeedsWork = new Set<string>();
        const allDistinctDossierStates = new Set<string>();

        const stateToTemplateMap = new Map<string, string>();

        const filterGroups: IFilterGroup[] = [];

        entities?.forEach(entry => {
            entry.memberIds.forEach(f => allDistinctPeople.add(f));

            allDistinctDossierStates.add(entry.dossierStatusId);
            if (entry.dossierStatusId) {
                stateToTemplateMap.set(entry.dossierStatusId, entry.dossierTemplateId);
            }

            const stats = this._dossierStatsService.get(entry.dossierId);

            if (!stats) {
                return;
            }

            Object.keys(stats?.fileCountPerWorkflowStatus).forEach(status => allDistinctFileStatus.add(status));

            if (stats.hasHintsNoRedactionsFilePresent) {
                allDistinctNeedsWork.add('hint');
            }
            if (stats.hasRedactionsFilePresent) {
                allDistinctNeedsWork.add('redaction');
            }
            if (stats.hasSuggestionsFilePresent) {
                allDistinctNeedsWork.add('suggestion');
            }
            if (stats.hasNoFlagsFilePresent) {
                allDistinctNeedsWork.add('none');
            }
        });

        const dossierStatesFilters = [...allDistinctDossierStates].map(
            id =>
                new NestedFilter({
                    id: id ?? 'undefined',
                    label: id
                        ? this._dossierStatesMapService.get(stateToTemplateMap.get(id), id).name
                        : this._translateService.instant('dossier-state.placeholder'),
                }),
        );

        filterGroups.push({
            slug: 'dossierStatesFilters',
            label: this._translateService.instant('filters.dossier-state'),
            icon: 'red:status',
            hide: dossierStatesFilters.length <= 1,
            filters: dossierStatesFilters,
            checker: dossierStateChecker,
        });

        const statusFilters = [...allDistinctFileStatus].map(
            (status: WorkflowFileStatus) =>
                new NestedFilter({
                    id: status,
                    label: this._translateService.instant(workflowFileStatusTranslations[status]),
                }),
        );
        statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]);
        filterGroups.push({
            slug: 'statusFilters',
            label: this._translateService.instant('filters.documents-status'),
            icon: 'red:status',
            filters: statusFilters,
            checker: (dossier: Dossier, filter: INestedFilter) => this._dossierStatusChecker(dossier, filter),
        });

        const peopleFilters = this._sortByName([...allDistinctPeople]).map(
            userId =>
                new NestedFilter({
                    id: userId,
                    label: this._userService.getName(userId),
                }),
        );

        filterGroups.push({
            slug: 'peopleFilters',
            label: this._translateService.instant('filters.people'),
            icon: 'red:user',
            filters: peopleFilters,
            checker: dossierMemberChecker,
        });

        if (!this.#isDocumine) {
            const needsWorkFilters = [...allDistinctNeedsWork].map(
                type =>
                    new NestedFilter({
                        id: type,
                        label: workloadTranslations[type],
                        metadata: {
                            shape: AnnotationShapeMap[type],
                            color$: this._defaultColorsService.getColor$(dossierTemplateId, annotationDefaultColorConfig[type]),
                        },
                    }),
            );
            needsWorkFilters.sort((a, b) => RedactionFilterSorter[a.id] - RedactionFilterSorter[b.id]);
            filterGroups.push({
                slug: 'needsWorkFilters',
                label: this._translateService.instant('filters.needs-work'),
                icon: 'red:needs-work',
                filterTemplate: needsWorkFilterTemplate,
                filters: needsWorkFilters,
                checker: (dossier: Dossier, filter: INestedFilter) => this._annotationFilterChecker(dossier, filter),
                matchAll: true,
            });
        }

        filterGroups.push({
            slug: 'quickFilters',
            filters: this._quickFilters(entities),
            checker: (dw: Dossier, filter: NestedFilter) => filter.checked && filter.checker(dw),
        });

        const dossierFilters = entities.map(
            dossier =>
                new NestedFilter({
                    id: dossier.dossierName,
                    label: dossier.dossierName,
                }),
        );
        filterGroups.push({
            slug: 'dossierNameFilter',
            label: this._translateService.instant('dossier-listing.filters.label'),
            icon: 'red:folder',
            filters: dossierFilters,
            filterceptionPlaceholder: this._translateService.instant('dossier-listing.filters.search'),
            checker: keyChecker('dossierName'),
        });

        return filterGroups;
    }

    private _openAddDossierDialog(dossierTemplateId: string): void {
        this._dialogService.openDialog('addDossier', { dossierTemplateId });
    }

    private _quickFilters(entities: Dossier[]): NestedFilter[] {
        const userId = this._currentUser.id;
        return [
            {
                id: 'owner',
                label: this._translateService.instant('dossier-listing.quick-filters.owner'),
                checker: dossierOwnerQuickChecker(userId),
                disabled: entities.filter(dossierOwnerQuickChecker(userId)).length === 0,
                helpModeKey: 'quick_filter_dossiers',
            },
            {
                id: 'member',
                label: this._translateService.instant('dossier-listing.quick-filters.member'),
                checker: dossierMemberQuickChecker(userId),
                disabled: entities.filter(dossierMemberQuickChecker(userId)).length === 0,
                helpModeKey: 'quick_filter_dossiers',
            },
        ].map(filter => new NestedFilter(filter));
    }

    private _dossierStatusChecker = (dossier: Dossier, filter: INestedFilter) => {
        const stats = this._dossierStatsService.get(dossier.id);
        return stats?.fileCountPerWorkflowStatus[filter.id];
    };

    private _annotationFilterChecker = (dossier: Dossier, filter: INestedFilter) => {
        const stats = this._dossierStatsService.get(dossier.id);
        switch (filter.id) {
            // case 'analysis': {
            // return stats.reanalysisRequired;
            // }
            case 'suggestion': {
                return stats.hasSuggestionsFilePresent;
            }
            case 'redaction': {
                return stats.hasRedactionsFilePresent;
            }
            case 'hint': {
                return stats.hasHintsNoRedactionsFilePresent;
            }
            case 'none': {
                return stats.hasNoFlagsFilePresent;
            }
        }
    };

    private _sortByName(ids: string[]) {
        return ids.sort((a, b) => this._userService.getName(a).localeCompare(this._userService.getName(b)));
    }
}
