package com.workfusion.odf.impl.processor;

import javax.inject.Inject;
import javax.inject.Named;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import com.workfusion.odf.api.domain.Document;
import com.workfusion.odf.api.domain.Transaction;
import com.workfusion.odf.core.Intake;
import com.workfusion.odf.core.Module;
import groovy.lang.Binding;
import org.codejargon.feather.Provides;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static com.workfusion.odf.impl.processor.DocumentOcrLinkProcessor.META_INFO_JSON;
import static com.workfusion.odf.impl.processor.DocumentOcrLinkProcessor.OCR_JSON_CONTEXT_NAME;
import static com.workfusion.odf.impl.processor.DocumentOcrLinkProcessor.OCR_TYPE_CONTEXT_NAME;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;

class DocumentOcrLinkProcessorTest {

    private static final String TOD_LINK = "https://tesla-minio-lb.workfusion.com:443/doc-upload/7aa77c64-c2ba-40d0-b4a2-307f2c1d741a/23a7149e-59fc-4c9b-a1a1-817236f01720/8acfc9a4-2b05-49df-9c21-3a4f51c2d7e5-xmlForCorrectedImage.xml";

    private static final String TOD_OCR_RESULT = "{\n"
            + "  \"xmlForCorrectedImage\": {\n"
            + "    \"original_document_url\": \"https://tesla-minio-lb.workfusion.com:443/doc-upload/8acfc9a4-2b05-49df-9c21-3a4f51c2d7e5.png\",\n"
            + "    \"ocr_export_format\": \"xmlForCorrectedImage\",\n"
            + "    \"ocr_document_format\": \"xml\",\n"
            + "    \"ocr_document_url\": \"" + TOD_LINK + "\"\n"
            + "  },\n"
            + "  \"xmlWithoutRecognitionVariants\": {\n"
            + "    \"ocr_doc_without_recognition_variants_url\": \"https://tesla-minio-lb.workfusion.com:443/doc-upload/7aa77c64-c2ba-40d0-b4a2-307f2c1d741a/23a7149e-59fc-4c9b-a1a1-817236f01720/8acfc9a4-2b05-49df-9c21-3a4f51c2d7e5-xmlWithoutRecognitionVariants.xml\",\n"
            + "    \"original_document_url\": \"https://tesla-minio-lb.workfusion.com:443/doc-upload/8acfc9a4-2b05-49df-9c21-3a4f51c2d7e5.png\",\n"
            + "    \"ocr_export_format\": \"xmlWithoutRecognitionVariants\",\n"
            + "    \"ocr_document_format\": \"xml\"\n"
            + "  }\n"
            + "}";

    private static final String DOCUMENT_ID = "1";

    @Inject
    private DocumentOcrLinkProcessor ocrLinkProcessor;

    private Binding context;
    private Map<String, String> params;

    private Document document;
    private Transaction transaction;

    private Module testModule = new Module() {

        @Provides
        public Binding binding() {
            return context;
        }

        @Provides
        @Named("botConfigParams")
        public Map<String, String> params() {
            return params;
        }
    };

    @BeforeEach
    void init() {
        params = new HashMap<>();
        params.put("_sys_doc_id", DOCUMENT_ID);

        context = new Binding();

        Document document = new Document();
        document.setId(DOCUMENT_ID);
        document.setOriginalDocumentLink("link1");

        transaction = new Transaction();
        transaction.setDocs(Collections.singletonList(document));

        Intake.init(context).params(params).override(testModule).injectFields(this).get();
    }

    @Test
    @DisplayName("should return document with same id")
    void shouldReturnDocumentWithSameId() {
        // given
        context.setVariable(OCR_TYPE_CONTEXT_NAME, "tod");
        context.setVariable(OCR_JSON_CONTEXT_NAME, TOD_OCR_RESULT);

        // when
        Transaction transformed = ocrLinkProcessor.transform(transaction);

        // then
        assertThat(transformed.getDocs())
                .hasSize(1)
                .extracting(Document::getId).containsExactly(DOCUMENT_ID);
    }

    @Test
    void shouldTransformDocumentWithTodType() {
        // given
        context.setVariable(OCR_TYPE_CONTEXT_NAME, "tod");
        context.setVariable(OCR_JSON_CONTEXT_NAME, TOD_OCR_RESULT);

        // when
        Transaction transformed = ocrLinkProcessor.transform(transaction);

        // then
        assertThat(transformed.getDocs())
                .hasSize(1)
                .allSatisfy(document -> {
                    assertThat(document.getTextLink()).isEqualTo(TOD_LINK);
                    assertThat(document.getAttribute(OCR_JSON_CONTEXT_NAME)).isEqualTo(TOD_OCR_RESULT);
                });
    }

    @Test
    @DisplayName("should return document with OCRed status")
    void shouldReturnDocumentWithOcredStatus() {
        // given
        context.setVariable(OCR_TYPE_CONTEXT_NAME, "tod");
        context.setVariable(OCR_JSON_CONTEXT_NAME, TOD_OCR_RESULT);

        assumeThat(transaction.getDocs())
                .hasSize(1)
                .allSatisfy(document -> {
                    assertThat(document.isOcredDocument()).isFalse();
                });

        // when
        Transaction transformed = ocrLinkProcessor.transform(transaction);

        // then
        assertThat(transformed.getDocs())
                .hasSize(1)
                .allSatisfy(document -> {
                    assertThat(document.isOcredDocument()).isTrue();
                });
    }

    @Test
    @DisplayName("should put meta_info_json parameter into document attributes")
    void shouldPutMetaInfoJsonParameterIntoDocumentAttributes() {
        //given
        final String parameter = "{ 'key': 'value' }";
        params.put(META_INFO_JSON, parameter);

        context.setVariable(OCR_TYPE_CONTEXT_NAME, "tod");
        context.setVariable(OCR_JSON_CONTEXT_NAME, TOD_OCR_RESULT);

        // when
        Transaction transformed = ocrLinkProcessor.transform(transaction);

        // then
        assertThat(transformed.getDocs())
                .hasSize(1)
                .allSatisfy(document -> {
                    assertThat(document.getAttribute(META_INFO_JSON)).isEqualTo(parameter);
                });
    }
}
