package ru.soune.nocopy.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ru.soune.nocopy.dto.search.GlobalSearchStartRequest;
import ru.soune.nocopy.dto.search.GlobalSearchStartResponse;
import ru.soune.nocopy.dto.search.GlobalSearchStatusResponse;
import ru.soune.nocopy.dto.violation.FileViolationSummaryDTO;
import ru.soune.nocopy.dto.violation.ViolationRequest;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.search.GlobalSearchTask;
import ru.soune.nocopy.entity.search.SearchStatus;
import ru.soune.nocopy.exception.NotFoundAuthToken;
import ru.soune.nocopy.repository.GlobalSearchTaskRepository;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.search.GlobalSearchService;
import ru.soune.nocopy.service.violation.ViolationService;

import java.util.*;

@Slf4j
@RestController
@RequestMapping("/api/v1/global-search")
@RequiredArgsConstructor
public class GlobalSearchController {

    private final AuthService authService;

    private final GlobalSearchService globalSearchService;

    private final GlobalSearchTaskRepository globalSearchTaskRepository;

    private final GlobalSearchTaskRepository searchTaskRepository;

    private final ViolationService violationService;

    @PostMapping("/start")
    public ResponseEntity<?> startSearch(
            @RequestBody GlobalSearchStartRequest request,
            @RequestHeader(value = "Authorization", required = false) String tokenHeader) {
        if (tokenHeader == null || tokenHeader.isBlank()) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        GlobalSearchStartResponse response = new GlobalSearchStartResponse();

        try {
            Long userId = authService.useUserAuthToken(tokenHeader);

            List<FileEntity> filesToProcess = globalSearchService.getFilesToProcess(request, userId);

            if (filesToProcess.isEmpty()) return ResponseEntity.ok().body("Files for search not found");

            String taskId = globalSearchService.startSearch(request, userId, filesToProcess);

            Optional<GlobalSearchTask> taskOptional = globalSearchTaskRepository.findById(taskId);

            if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found");

            GlobalSearchTask task = taskOptional.orElseThrow();

            response.setTaskId(taskId);
            response.setStatus(SearchStatus.ACCEPTED.name());
            response.setTotalFiles(task.getTotalFiles());
        } catch (NotFoundAuthToken e) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        return ResponseEntity.ok(response);
    }

    @GetMapping("/actual-task")
    public ResponseEntity<?> getStatus(@RequestHeader(value = "Authorization", required = false) String tokenHeader) {

        if (tokenHeader == null || tokenHeader.isBlank()) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        Optional<GlobalSearchTask> taskOptional;

        try {
            Long userId = authService.useUserAuthToken(tokenHeader);

            taskOptional = searchTaskRepository.findByUserIdAndStatus(userId,
                    "PROCESSING");

            if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found");
        } catch (NotFoundAuthToken e) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        return ResponseEntity.ok(taskOptional.get());
    }

    @GetMapping("/violation-summary")
    public ResponseEntity<?> getSummary(@RequestHeader(value = "Authorization", required = false) String tokenHeader) {

        if (tokenHeader == null || tokenHeader.isBlank()) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        List<FileViolationSummaryDTO> fileViolationsSummary;

        try {
            Long userId = authService.useUserAuthToken(tokenHeader);

            fileViolationsSummary = violationService.getFileViolationsSummary(userId);

            if (fileViolationsSummary.isEmpty()) return ResponseEntity.ok().body("Violations summary not found");
        } catch (NotFoundAuthToken e) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        return ResponseEntity.ok(fileViolationsSummary);
    }


    @PostMapping("/violation-summary-with-files")
    public ResponseEntity<?> getViolations(@RequestBody ViolationRequest request) {
        if (request.getToken() == null || request.getToken().isBlank()) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", request.getToken());
            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        try {
            Long userId = authService.useUserAuthToken(request.getToken());

            Page<FileViolationSummaryDTO> result = violationService.getFileViolationsSummary(
                    userId, request.getFileName(), request.getSortDirection(),
                    request.getPage(), request.getSize(), request.getStartDate(), request.getEndDate());

            return ResponseEntity.ok(result);
        } catch (NotFoundAuthToken e) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", request.getToken());

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }
    }

    @GetMapping("/status/{taskId}")
    public ResponseEntity<?> getStatus(@PathVariable String taskId,
            @RequestHeader(value = "Authorization", required = false) String tokenHeader) {

        if (tokenHeader == null || tokenHeader.isBlank()) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }
        GlobalSearchStatusResponse response;

        try {
            Long userId = authService.useUserAuthToken(tokenHeader);

            Optional<GlobalSearchTask> taskOptional = searchTaskRepository.findByTaskIdAndUserId(taskId, userId);

            if (taskOptional.isEmpty()) return ResponseEntity.ok().body("Task not found");

            GlobalSearchTask task = taskOptional.orElseThrow();

            int progress = task.getTotalFiles() > 0 ? task.getProcessedFiles() * 100 / task.getTotalFiles() : 0;

            response = new GlobalSearchStatusResponse();
            response.setTaskId(taskId);
            response.setStatus(task.getStatus());
            response.setProgress(progress);
        } catch (NotFoundAuthToken e) {
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("token", tokenHeader);

            return ResponseEntity.ok().body(Map.of("error", errorData));
        }

        return ResponseEntity.ok(response);
    }
}
