package org.raddatz.familienarchiv.ocr;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.raddatz.familienarchiv.ocr.OcrStatusDTO;
import org.raddatz.familienarchiv.exception.DomainException;
import org.raddatz.familienarchiv.exception.ErrorCode;
import org.raddatz.familienarchiv.document.Document;
import org.raddatz.familienarchiv.document.DocumentStatus;
import org.raddatz.familienarchiv.ocr.OcrJobDocumentRepository;
import org.raddatz.familienarchiv.ocr.OcrJobRepository;
import org.raddatz.familienarchiv.document.DocumentService;
import org.raddatz.familienarchiv.filestorage.FileService;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
@RequiredArgsConstructor
@Slf4j
public class OcrService {

    private final OcrHealthClient ocrHealthClient;
    private final DocumentService documentService;
    private final OcrJobRepository ocrJobRepository;
    private final OcrJobDocumentRepository ocrJobDocumentRepository;
    private final OcrAsyncRunner ocrAsyncRunner;

    public OcrJob getJob(UUID jobId) {
        return ocrJobRepository.findById(jobId)
                .orElseThrow(() -> DomainException.notFound(
                        ErrorCode.OCR_JOB_NOT_FOUND, "OCR job not found: " + jobId));
    }

    public OcrStatusDTO getDocumentOcrStatus(UUID documentId) {
        List<OcrDocumentStatus> activeStatuses = List.of(
                OcrDocumentStatus.PENDING, OcrDocumentStatus.RUNNING);

        Optional<OcrJobDocument> activeJobDoc = ocrJobDocumentRepository
                .findFirstByDocumentIdAndStatusIn(documentId, activeStatuses);

        if (activeJobDoc.isEmpty()) {
            return OcrStatusDTO.builder().status("NONE").build();
        }

        OcrJobDocument jobDoc = activeJobDoc.get();
        return OcrStatusDTO.builder()
                .status(jobDoc.getStatus().name())
                .jobId(jobDoc.getJobId())
                .currentPage(jobDoc.getCurrentPage())
                .totalPages(jobDoc.getTotalPages())
                .build();
    }

    public UUID startOcr(UUID documentId, ScriptType scriptTypeOverride, UUID userId) {
        return startOcr(documentId, scriptTypeOverride, userId, false);
    }

    public UUID startOcr(UUID documentId, ScriptType scriptTypeOverride, UUID userId,
                          boolean useExistingAnnotations) {
        Document doc = documentService.getDocumentById(documentId);

        if (doc.getStatus() == DocumentStatus.PLACEHOLDER) {
            throw DomainException.badRequest(ErrorCode.OCR_DOCUMENT_NOT_UPLOADED,
                    "Document has no file attached: " + documentId);
        }

        if (!ocrHealthClient.isHealthy()) {
            throw DomainException.internal(ErrorCode.OCR_SERVICE_UNAVAILABLE,
                    "OCR service is not available");
        }

        if (scriptTypeOverride != null) {
            documentService.updateScriptType(documentId, scriptTypeOverride);
            if (scriptTypeOverride == ScriptType.HANDWRITING_KURRENT) {
                documentService.addTrainingLabel(documentId, TrainingLabel.KURRENT_RECOGNITION);
            }
        }

        OcrJob job = OcrJob.builder()
                .totalDocuments(1)
                .createdBy(userId)
                .status(OcrJobStatus.PENDING)
                .build();
        job = ocrJobRepository.save(job);

        OcrJobDocument jobDoc = OcrJobDocument.builder()
                .jobId(job.getId())
                .documentId(documentId)
                .status(OcrDocumentStatus.PENDING)
                .build();
        ocrJobDocumentRepository.save(jobDoc);

        ocrAsyncRunner.runSingleDocument(job.getId(), documentId, userId, useExistingAnnotations);
        return job.getId();
    }
}
