package com.arms.api.wiki.service;

import com.arms.api.search_engine.model.dto.SearchDTO;
import com.arms.api.search_engine.model.vo.SearchResultVO;
import com.arms.api.wiki.model.*;
import com.arms.egovframework.javaservice.esframework.esquery.SimpleQuery;
import com.arms.egovframework.javaservice.esframework.esquery.filter.RangeQueryFilter;
import com.arms.egovframework.javaservice.esframework.model.dto.esquery.SortDTO;
import com.arms.egovframework.javaservice.esframework.model.vo.DocumentResultWrapper;
import com.arms.egovframework.javaservice.esframework.repository.common.EsCommonRepositoryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.arms.egovframework.javaservice.esframework.esquery.highlight.EsHighlightQuery.esHighlightAll;

@Service
@Slf4j
@RequiredArgsConstructor
public class WikiServiceImpl implements WikiService {

    private final EsCommonRepositoryWrapper<WikiEntity> esCommonRepositoryWrapper;

    @Override
    public WikiVO getWiki(String wikiId) {
        WikiEntity docs = esCommonRepositoryWrapper.findRecentDocByRecentId(wikiId);
        return WikiConverter.toVO(docs);
    }

    @Override
    public WikiVO getWiki(String wikiId, Long version) {
        WikiEntity docs = esCommonRepositoryWrapper.findHits(
                        SimpleQuery.termQueryFilter("wiki_id", wikiId).andTermQueryFilter("version", version)).findFirst();
        return WikiConverter.toVO(docs);
    }

    @Override
    public WikiVersionsVO getWikiVersions(String wikiId, int size, int page) {
        WikiDTO wikiDTO = new WikiDTO();
        wikiDTO.setSize(size);
        wikiDTO.setPage(page);
        wikiDTO.setIncludeFields(new String[]{"wiki_id", "version", "author", "recent", "created_date", "updated_date"});
        DocumentResultWrapper<WikiEntity> wiki = esCommonRepositoryWrapper.findHits(SimpleQuery.search(wikiDTO)
                .andTermQueryFilter("wiki_id", wikiId)
                .orderBy(SortDTO.builder().field("updated_date").sortType("desc").build())
        );
        Long totalHits = wiki.getTotalHits();
        List<WikiEntity> docs = wiki.toDocs();
        List<WikiVersionVO> wikiVersions = new ArrayList<>();

        for (WikiEntity wikiEntity : docs) {
            wikiVersions.add(WikiVersionVO.builder()
                    .wikiId(wikiEntity.getWikiId())
                    .version(wikiEntity.getVersion())
                    .author(wikiEntity.getAuthor())
                    .recent(wikiEntity.isRecent())
                    .createdDate(wikiEntity.getCreatedDate())
                    .updatedDate(wikiEntity.getUpdatedDate())
                    .build());
        }

        return WikiVersionsVO.builder().totalHits(totalHits).wikiVersions(wikiVersions).build();
    }

    @Override
    public String createWiki(WikiDTO wikiDTO) {
        WikiEntity savedEntity = esCommonRepositoryWrapper.save(wikiDTO.createEntity());
        return savedEntity.generateIdWithVersion();
    }

    @Override
    public String updateWiki(WikiDTO wikiDTO) {
        WikiEntity fetchedWiki = esCommonRepositoryWrapper.findRecentDocByRecentId(wikiDTO.getWikiId());

        if (fetchedWiki == null) {
            throw new IllegalArgumentException("존재하지 않는 Wiki 문서");
        }

        fetchedWiki.updateWikiEntity(
                wikiDTO.createEntityWithVersionUp(fetchedWiki.getVersion())
        );

        WikiEntity savedEntity = esCommonRepositoryWrapper.save(fetchedWiki);

        return savedEntity.generateIdWithVersion();
    }

    @Override
    public void changeRecent(WikiDTO wikiDTO) {
        DocumentResultWrapper<WikiEntity> currentRecent = esCommonRepositoryWrapper.findRecentHits(SimpleQuery.termQueryFilter("wiki_id", wikiDTO.getWikiId()));
        currentRecent.toHitDocs().forEach(
                a-> {
                    String index = a.getIndex();
                    WikiEntity content = a.getContent();
                    content.setRecent(false);
                    esCommonRepositoryWrapper.modifyWithIndexName(content,index);
                }
        );

        DocumentResultWrapper<WikiEntity> wiki = esCommonRepositoryWrapper.findHits(SimpleQuery.termQueryFilter("wiki_id", wikiDTO.getWikiId()).andTermQueryFilter("version", wikiDTO.getVersion()));
        wiki.toHitDocs().forEach(
                a -> {
                    String index = a.getIndex();
                    WikiEntity content = a.getContent();
                    content.setRecent(true);
                    esCommonRepositoryWrapper.modifyWithIndexName(content,index);
                }
        );
    }

    @Override
    public String deleteWiki(String wikiId) {
        WikiEntity wikiEntity = esCommonRepositoryWrapper.findRecentDocByRecentId(wikiId);
        if (wikiEntity == null) {
            throw new IllegalArgumentException("존재하지 않는 위키 문서");
        }
        List<WikiEntity> docs = esCommonRepositoryWrapper.findHits(SimpleQuery.termQueryMust("wikiId", wikiId)).toDocs();
        for (WikiEntity doc : docs) {
            esCommonRepositoryWrapper.deleteById(doc.getId());
        }

        return wikiId;
    }

    @Override
    public SearchResultVO<WikiEntity> searchWiki(SearchDTO searchDTO) {
        String startDate = searchDTO.getStartDate();
        String endDate = searchDTO.getEndDate();
        searchDTO.setSize(10);

        String filterFieldName = getFilterFieldName(searchDTO.getFilter().getName());

        DocumentResultWrapper<WikiEntity> hits = esCommonRepositoryWrapper.findRecentHits(
                SimpleQuery.search(searchDTO)
                        .andQueryStringFilter(searchDTO.getSearchString())
                        .andTermsQueryFilter(filterFieldName, searchDTO.getFilter().getValues())
                        .andRangeQueryFilter(RangeQueryFilter.of("@timestamp").betweenDate(startDate, endDate))
                        .highlight(esHighlightAll())
        );

        return SearchResultVO.<WikiEntity>builder()
                .totalResultDocs(hits.getTotalHits())
                .searchResultDocs(hits.toHitDocs())
                .build();
    }

    private String getFilterFieldName(String filterName) {
        if (filterName != null && !filterName.isBlank() && filterName.equals("log")) {
            return "contents";
        }
        return null;
    }

    class WikiConverter {
        public static WikiVO toVO(WikiEntity entity) {
            if (entity == null) {
                return null;
            }

            return WikiVO.builder()
                    .id(entity.getId())
                    .contents(entity.getContents())
                    .wikiId(entity.getWikiId())
                    .author(entity.getAuthor())
                    .version(entity.getVersion())
                    .pdServiceId(entity.getPdServiceId())
                    .createdDate(entity.getCreatedDate())
                    .updatedDate(entity.getUpdatedDate())
                    .build();
        }

        public static WikiVO emptyVO(String id) {
            return WikiVO.builder().id(id)
                    .contents("Empty - Document :: id → " + id)
                    .version(0L)
                    .diagramXmls(Collections.emptyList())
                    .pdServiceId("")
                    .author("")
                    .build();
        }
    }
}
