package ru.soune.nocopy.handler;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.dto.BaseRequest;
import ru.soune.nocopy.dto.BaseResponse;
import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.file.ImageSearchRequest;
import ru.soune.nocopy.dto.file.YandexSearchResponse;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.service.file.CheckCounterService;
import ru.soune.nocopy.service.search.SearchImageService;
import ru.soune.nocopy.service.search.GoogleVisionSearchService;
import ru.soune.nocopy.service.tariff.TariffConstants;
import ru.soune.nocopy.service.tariff.TariffInfoService;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeoutException;

@Slf4j
@Component
@RequiredArgsConstructor
public class ImageFoundRequestHandler implements RequestHandler {

    private final ObjectMapper objectMapper;

    private final SearchImageService searchImageService;

    private final GoogleVisionSearchService googleVisionSearchService;

    private final CheckCounterService checkCounterService;

    private final FileEntityRepository fileEntityRepository;

    private final TariffInfoService tariffInfoService;

    @Override
    public BaseResponse handle(BaseRequest request) throws Exception {
        ImageSearchRequest imageSearchRequest = objectMapper.convertValue(request.getMessageBody(),
                ImageSearchRequest.class);

        String fileId = imageSearchRequest.getFileId();

        FileEntity fileEntity = fileEntityRepository.findById(fileId)
                .orElseThrow(() -> {
                    throw new NotValidFieldException("File not found", new BaseResponse(20007,
                            MessageCode.FILE_NOT_FOUND.getCode(), MessageCode.FILE_NOT_FOUND.getDescription(),
                            Map.of("fileId",fileId)));
                });

//        YandexSearchResponse response = yandexSearchService.searchByFileEntity(fileEntity);

        //TODO uncommited when add billing
//        GoogleVisionSearchResponse googleVisionSearchResponse = googleVisionSearchService.searchByFileEntity(fileId);

        String searchResponseYandex;
        String searchResponseGoogle;
        List<YandexSearchResponse.ImageResult> allUniqueImages;
        try {
            searchResponseYandex = searchImageService.searchReverseByPublicUrl(fileEntity, "yandex_reverse_image",
                    "visual_matches");
            log.info("searchResponseYandex OK");
            List<YandexSearchResponse.ImageResult> allYandexImages = searchImageService.getAllImagesWithoutPagination(
                    searchResponseYandex, "visual_matches");
            searchResponseGoogle = searchImageService.searchReverseByPublicUrl(fileEntity, "google_lens",
                    "exact_matches");

            log.info("searchResponseGoogle OK");
            List<YandexSearchResponse.ImageResult> allGoogleImages = searchImageService.getAllImagesWithoutPagination(
                    searchResponseGoogle, "exact_matches");
            allUniqueImages = searchImageService.removeDuplicateUrls(allYandexImages,
                    allGoogleImages);
            log.info("allUniqueImages OK");

        } catch (TimeoutException e) {
            log.warn("Search timeout for file {}, returning empty results", fileId);
            return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
                    "Search completed (partial)", Map.of(
                    "results", List.of(),
                    "total", 0,
                    "searchStatus", "timeout"
            ));
        } catch (IOException e) {
            log.error("Search failed for file {}", fileId, e);
            return new BaseResponse(request.getMsgId(), 20007,
                    "Search service temporarily unavailable",
                    Map.of("fileId", fileId));
        }

        tariffInfoService.writeOffTokens(fileEntity.getUserId(), TariffConstants.TOKEN_VALUE_FOR_SEARCH);

        checkCounterService.incrementCheckCount(fileEntity.getUserId(), fileEntity.getMimeType());

        int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1;
        int pageSize = 5;

        List<YandexSearchResponse.ImageResult> pagedResults = searchImageService.paginateResults(allUniqueImages, page,
                pageSize * 2);

        YandexSearchResponse finalResponse = new YandexSearchResponse();
        finalResponse.setImages(pagedResults);
        finalResponse.setPage(page);
        finalResponse.setPageSize(pageSize * 2);
        finalResponse.setTotalResults(allUniqueImages.size());
        finalResponse.setTotalPages((int) Math.ceil((double) allUniqueImages.size() / (pageSize * 2)));

        return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
                MessageCode.SUCCESS.getDescription(), finalResponse);
    }
}
