import { Entity } from '@iqser/common-ui';
import { StatusSorter } from '../shared';
import {
    isFullProcessingStatuses,
    isProcessingStatuses,
    OCR_STATES,
    PENDING_STATES,
    PROCESSING_STATES,
    ProcessingFileStatus,
    ProcessingFileStatuses,
    WorkflowFileStatus,
    WorkflowFileStatuses,
} from './types';
import { IFile } from './file';
import { FileAttributes } from '../file-attributes';
import { ARCHIVE_ROUTE, DOSSIERS_ROUTE } from '../dossiers';
import { ProcessingType, ProcessingTypes } from '../dossier-stats';

export class File extends Entity<IFile> implements IFile {
    readonly added?: string;
    readonly allManualRedactionsApplied: boolean;
    readonly analysisDuration?: number;
    readonly analysisRequired: boolean;
    readonly approvalDate?: string;
    readonly assignee?: string;
    readonly dictionaryVersion?: number;
    readonly dossierDictionaryVersion?: number;
    readonly dossierId: string;
    readonly excluded: boolean;
    readonly excludedFromAutomaticAnalysis: boolean;
    readonly fileAttributes: FileAttributes;
    readonly fileId: string;
    readonly filename: string;
    readonly fileSize: number;
    readonly hasAnnotationComments: boolean;
    readonly hasHints: boolean;
    readonly hasImages: boolean;
    readonly hasRedactions: boolean;
    readonly hasUpdates: boolean;
    readonly lastOCRTime?: string;
    readonly softDeletedTime?: string;
    readonly lastProcessed?: string;
    readonly lastLayoutProcessed?: string;
    readonly lastReviewer?: string;
    readonly lastApprover?: string;
    readonly lastUpdated?: string;
    readonly lastUploaded?: string;
    readonly legalBasisVersion?: number;
    readonly numberOfAnalyses: number;
    readonly numberOfPages: number;
    readonly rulesVersion?: number;
    readonly uploader?: string;
    readonly excludedPages: number[];
    readonly hasSuggestions: boolean;
    readonly processingStatus: ProcessingFileStatus;
    readonly workflowStatus: WorkflowFileStatus;
    readonly fileManipulationDate: string;
    readonly redactionModificationDate: string;
    readonly lastManualChangeDate?: string;
    readonly hasHighlights: boolean;
    readonly dossierArchived: boolean;
    readonly dossierTemplateId: string;
    readonly numberOfPagesToOCR: number;
    readonly numberOfOCRedPages: number;

    readonly statusSort: number;
    readonly cacheIdentifier?: string;
    readonly hintsOnly: boolean;
    readonly hasNone: boolean;
    readonly isNew: boolean;
    readonly isError: boolean;
    readonly isProcessing: boolean;
    readonly isFullProcessing: boolean;
    readonly isOcrProcessing: boolean;
    readonly isInitialProcessing: boolean;
    readonly isApproved: boolean;
    readonly isUnprocessed: boolean;
    readonly isUnderReview: boolean;
    readonly isUnderApproval: boolean;
    readonly canBeApproved: boolean;
    readonly canBeOpened: boolean;
    readonly canBeOCRed: boolean;

    readonly processingType: ProcessingType;

    constructor(file: IFile, readonly reviewerName: string) {
        super(file);
        this.added = file.added;
        this.allManualRedactionsApplied = !!file.allManualRedactionsApplied;
        this.analysisDuration = file.analysisDuration;
        this.analysisRequired = !!file.analysisRequired && !file.excluded;
        this.approvalDate = file.approvalDate;
        this.assignee = file.assignee;
        this.dictionaryVersion = file.dictionaryVersion;
        this.dossierDictionaryVersion = file.dossierDictionaryVersion;
        this.dossierId = file.dossierId;
        this.excluded = !!file.excluded;
        this.excludedFromAutomaticAnalysis = !!file.excludedFromAutomaticAnalysis;
        this.fileId = file.fileId;
        this.filename = file.filename;
        this.fileSize = file.fileSize;
        this.hasAnnotationComments = !!file.hasAnnotationComments;
        this.hasHints = !!file.hasHints;
        this.hasImages = !!file.hasImages;
        this.hasRedactions = !!file.hasRedactions;
        this.hasUpdates = !!file.hasUpdates;
        this.lastOCRTime = file.lastOCRTime;
        this.softDeletedTime = file.softDeletedTime;
        this.lastProcessed = file.lastProcessed;
        this.lastLayoutProcessed = file.lastLayoutProcessed;
        this.lastReviewer = file.lastReviewer;
        this.lastApprover = file.lastApprover;
        this.lastUpdated = file.lastUpdated;
        this.lastUploaded = file.lastUploaded;
        this.legalBasisVersion = file.legalBasisVersion;
        this.numberOfAnalyses = file.numberOfAnalyses;
        this.processingStatus = file.processingStatus;
        this.workflowStatus = file.workflowStatus;
        this.isError = this.processingStatus === ProcessingFileStatuses.ERROR;
        this.isUnprocessed = this.processingStatus === ProcessingFileStatuses.UNPROCESSED;
        this.numberOfPages = this.isError ? 0 : file.numberOfPages ?? 0;
        this.rulesVersion = file.rulesVersion;
        this.uploader = file.uploader;
        this.excludedPages = file.excludedPages || [];
        this.hasSuggestions = !!file.hasSuggestions;
        this.fileManipulationDate = file.fileManipulationDate ?? '';
        this.redactionModificationDate = file.redactionModificationDate ?? '';
        this.lastManualChangeDate = file.lastManualChangeDate;
        this.hasHighlights = file.hasHighlights;
        this.dossierArchived = file.dossierArchived;
        this.dossierTemplateId = file.dossierTemplateId;
        this.numberOfPagesToOCR = file.numberOfPagesToOCR ?? 0;
        this.numberOfOCRedPages = file.numberOfOCRedPages ?? 0;

        this.statusSort = StatusSorter[this.workflowStatus];
        this.cacheIdentifier = btoa(`${this.fileManipulationDate}${file.lastOCRTime}${file.ocrEndTime}${file.lastLayoutProcessed}`);
        this.hintsOnly = this.hasHints && !this.hasRedactions;
        this.hasNone = !this.hasRedactions && !this.hasHints && !this.hasSuggestions;
        this.isProcessing = isProcessingStatuses.includes(this.processingStatus);
        this.isFullProcessing = isFullProcessingStatuses.includes(this.processingStatus);
        this.isOcrProcessing = this.processingStatus === ProcessingFileStatuses.OCR_PROCESSING;
        this.isInitialProcessing = this.isProcessing && this.numberOfAnalyses === 0;
        this.isApproved = this.workflowStatus === WorkflowFileStatuses.APPROVED;
        this.isNew = this.workflowStatus === WorkflowFileStatuses.NEW;
        this.isUnderReview = this.workflowStatus === WorkflowFileStatuses.UNDER_REVIEW;
        this.isUnderApproval = this.workflowStatus === WorkflowFileStatuses.UNDER_APPROVAL;
        this.canBeApproved = !this.hasSuggestions && !this.isProcessing && !this.isError;
        this.canBeOpened = (!this.isError && !this.isUnprocessed && this.numberOfAnalyses > 0) || this.excluded;
        this.canBeOCRed =
            !this.excluded &&
            !this.lastOCRTime &&
            this.numberOfAnalyses !== 0 &&
            (this.isNew || this.isUnderReview || this.isUnderApproval);

        this.fileAttributes =
            file.fileAttributes && file.fileAttributes.attributeIdToValue ? file.fileAttributes : { attributeIdToValue: {} };

        this.processingType = this.#processingType;
    }

    get deleted(): boolean {
        return !!this.softDeletedTime;
    }

    get id(): string {
        return this.fileId;
    }

    get searchKey(): string {
        return this.filename;
    }

    get routerLink(): string | undefined {
        const routerPath = this.dossierArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE;
        return this.canBeOpened ? `/main/${this.dossierTemplateId}/${routerPath}/${this.dossierId}/file/${this.fileId}` : undefined;
    }

    get #processingType(): ProcessingType {
        if (PENDING_STATES.includes(this.processingStatus)) {
            return ProcessingTypes.pending;
        }
        if (PROCESSING_STATES.includes(this.processingStatus)) {
            return ProcessingTypes.processing;
        }
        if (OCR_STATES.includes(this.processingStatus)) {
            return ProcessingTypes.ocr;
        }
        return ProcessingTypes.processed;
    }

    isPageExcluded(page: number): boolean {
        return this.excludedPages.includes(page);
    }
}
