import {
    AfterViewInit,
    ChangeDetectorRef,
    Component,
    computed,
    ElementRef,
    HostListener,
    Input,
    NgZone,
    OnDestroy,
    OnInit,
    ViewChild,
} from '@angular/core';
import { Roles } from '@users/roles';
import {
    CircleButtonComponent,
    CircleButtonTypes,
    DisableStopPropagationDirective,
    getConfig,
    HelpModeService,
    IqserAllowDirective,
    IqserDialog,
    IqserPermissionsService,
    isIqserDevMode,
    LoadingService,
} from '@iqser/common-ui';
import { Bind, Debounce, OnDetach } from '@iqser/common-ui/lib/utils';
import { File } from '@red/domain';
import { PermissionsService } from '@services/permissions.service';
import { download } from '@utils/file-download-utils';
import { saveAs } from 'file-saver';
import JSZip from 'jszip';
import { firstValueFrom } from 'rxjs';
import { Router, RouterLink } from '@angular/router';
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
import { AnnotationActionsService } from '../../services/annotation-actions.service';
import { FileDataService } from '../../services/file-data.service';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { MultiSelectService } from '../../services/multi-select.service';
import { ViewSwitchComponent } from '../view-switch/view-switch.component';
import { DocumineExportComponent } from '../documine-export/documine-export.component';
import { NgIf } from '@angular/common';
import { ProcessingIndicatorComponent } from '@shared/components/processing-indicator/processing-indicator.component';
import { UserManagementComponent } from '../user-management/user-management.component';
import { TranslateModule } from '@ngx-translate/core';
import { InitialsAvatarComponent } from '@common-ui/users';
import { FileActionsComponent } from '../../../shared-dossiers/components/file-actions/file-actions.component';
import { TablesService } from '../../services/tables.service';
import { ALL_HOTKEYS } from '../../utils/constants';
import { AnnotationDrawService } from '../../../pdf-viewer/services/annotation-draw.service';
import { FileManagementService } from '@services/files/file-management.service';
import { MatDialog } from '@angular/material/dialog';

@Component({
    selector: 'redaction-file-header',
    templateUrl: './file-header.component.html',
    styleUrls: ['./file-header.component.scss'],
    standalone: true,
    imports: [
        ViewSwitchComponent,
        DocumineExportComponent,
        NgIf,
        ProcessingIndicatorComponent,
        UserManagementComponent,
        TranslateModule,
        InitialsAvatarComponent,
        FileActionsComponent,
        CircleButtonComponent,
        IqserAllowDirective,
        DisableStopPropagationDirective,
        RouterLink,
    ],
})
export class FileHeaderComponent implements OnInit, AfterViewInit, OnDetach, OnDestroy {
    @ViewChild('actionsWrapper', { static: false }) private readonly _actionsWrapper: ElementRef;
    protected readonly roles = Roles;
    protected readonly circleButtonTypes = CircleButtonTypes;
    @Input() file: File;
    readonly lastAssignee = computed(() => this.getLastAssignee());
    readonly isIqserDevMode = isIqserDevMode();
    readonly isDocumine = getConfig().IS_DOCUMINE;
    width: number;
    fullScreen = false;

    constructor(
        private readonly _changeRef: ChangeDetectorRef,
        private readonly _iqserPermissionsService: IqserPermissionsService,
        private readonly _loadingService: LoadingService,
        private readonly _pdf: PdfViewer,
        private readonly _annotationDrawService: AnnotationDrawService,
        private readonly _tablesService: TablesService,
        private readonly _router: Router,
        private readonly _ngZone: NgZone,
        private readonly _helpModeService: HelpModeService,
        private readonly _annotationActionsService: AnnotationActionsService,
        private readonly _fileDataService: FileDataService,
        private readonly _annotationManager: REDAnnotationManager,
        private readonly _dialog: MatDialog,
        private readonly _fileManagementService: FileManagementService,
        private readonly _multiSelectService: MultiSelectService,
        readonly state: FilePreviewStateService,
        readonly permissionsService: PermissionsService,
    ) {}

    ngOnInit() {
        document.documentElement.addEventListener('fullscreenchange', this.fullscreenListener);
    }

    ngAfterViewInit() {
        const _observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
            this._updateItemWidth(entries[0]);
        });
        _observer.observe(this._actionsWrapper.nativeElement);
    }

    ngOnDetach() {
        document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener);
    }

    ngOnDestroy() {
        document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener);
    }

    async downloadOriginalFile({ cacheIdentifier, dossierId, fileId, filename }: File) {
        const originalFile = this._fileManagementService.downloadOriginal(dossierId, fileId, 'response', cacheIdentifier);
        download(await firstValueFrom(originalFile), filename);
    }

    getLastAssignee() {
        const { isApproved, lastReviewer, lastApprover } = this.state.file();
        const isRss = this._iqserPermissionsService.has(this.roles.getRss);
        return isApproved ? (isRss ? lastReviewer : lastApprover) : lastReviewer;
    }

    async getTables() {
        this._loadingService.start();

        const currentPage = this._pdf.currentPage();
        const tables = await this._tablesService.get(this.state.dossierId, this.state.fileId, this._pdf.currentPage());
        await this._annotationDrawService.drawTables(tables, currentPage, this.state.dossierTemplateId);

        const filename = this.state.file().filename;
        const zip = new JSZip();

        tables.forEach((t, index) => {
            const blob = new Blob([atob(t.csvAsBytes)], {
                type: 'text/csv;charset=utf-8',
            });
            zip.file(filename + '_page' + currentPage + '_table' + (index + 1) + '.csv', blob);
        });

        saveAs(await zip.generateAsync({ type: 'blob' }), filename + '_tables.zip');

        this._loadingService.stop();
    }

    toggleFullScreen() {
        this.fullScreen = !this.fullScreen;
        if (this.fullScreen) {
            this.#openFullScreen();
        } else {
            this.closeFullScreen();
        }
    }

    closeFullScreen() {
        if (!!document.fullscreenElement && document.exitFullscreen) {
            document.exitFullscreen().then();
        }
    }

    @Bind()
    fullscreenListener() {
        if (!document.fullscreenElement) {
            this.fullScreen = false;
        }
    }

    @HostListener('document:keyup', ['$event'])
    handleKeyEvent($event: KeyboardEvent) {
        if (this._router.url.indexOf('/file/') < 0) {
            return;
        }

        if (!ALL_HOTKEYS.includes($event.key) || this._dialog.openDialogs.length) {
            return;
        }

        if (['Escape'].includes($event.key)) {
            $event.preventDefault();
            if (this._annotationManager.resizingAnnotationId) {
                const resizedAnnotation = this._fileDataService
                    .annotations()
                    .find(annotation => annotation.id === this._annotationManager.resizingAnnotationId);
                this._annotationActionsService.cancelResize(resizedAnnotation).then();
            }

            if (this._annotationManager.selected.length) {
                this._annotationManager.deselectAll();
            }

            if (this._multiSelectService.active()) {
                this._multiSelectService.deactivate();
            }
            this.fullScreen = false;
            this.closeFullScreen();
            this._changeRef.markForCheck();
        }

        if (!$event.ctrlKey && !$event.metaKey && ['f', 'F'].includes($event.key)) {
            // if you type in an input, don't toggle full-screen
            if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) {
                return;
            }
            this.toggleFullScreen();
            return;
        }

        if (['h', 'H'].includes($event.key)) {
            if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) {
                return;
            }
            this._ngZone.run(() => {
                window.focus();
                this._helpModeService.activateHelpMode(false);
            });
            return;
        }
    }

    #openFullScreen() {
        const documentElement = document.documentElement;
        if (documentElement.requestFullscreen) {
            documentElement.requestFullscreen().then();
        }
    }

    @Debounce(30)
    private _updateItemWidth(entry: ResizeObserverEntry): void {
        this.width = entry.contentRect.width;
        this._changeRef.detectChanges();
    }
}
