package kz.konturai.parser.controller;

import jakarta.validation.Valid;
import kz.konturai.parser.dto.*;
import kz.konturai.parser.model.MarketingAnalysisV3Document;
import kz.konturai.parser.model.MarketingStrategy;
import kz.konturai.parser.model.PostingTask;
import kz.konturai.parser.service.JwtService;
import kz.konturai.parser.service.MarketingAnalysisV3Service;
import kz.konturai.parser.service.MarketingStrategyV3Service;
import kz.konturai.parser.service.MinIOService;
import kz.konturai.parser.service.PostingTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/marketing/v3")
@RequiredArgsConstructor
@Slf4j
public class MarketingAnalysisV3Controller {

    private final MarketingAnalysisV3Service analysisService;
    private final MarketingStrategyV3Service strategyService;
    private final PostingTaskService         postingTaskService;
    private final MinIOService               minIOService;
    private final JwtService                 jwtService;

    private String extractUserIdFromHeader(String authHeader) {
        if (authHeader == null || authHeader.isEmpty()) return null;
        try {
            return jwtService.extractUserIdFromHeader(authHeader);
        } catch (Exception e) {
            return null;
        }
    }

    // =========================================================
    // ANALYSIS
    // =========================================================

    @PostMapping("/start")
    public ResponseEntity<?> startAnalysis(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @RequestBody @Valid MarketingAnalysisV3Request request) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            String analysisId = analysisService.createAndStartAnalysis(request, userId);
            return ResponseEntity.accepted().body(ApiResponse.success("Анализ запущен",
                    Map.of("analysisId", analysisId, "message", "Analysis V3 started")));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/{id}")
    public ResponseEntity<?> getAnalysisById(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String id) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingAnalysisV3Document> analysisOpt = analysisService.getAnalysisById(id);
            if (analysisOpt.isEmpty()) return notFoundResponse("Анализ не найден");

            MarketingAnalysisV3Document analysis = analysisOpt.get();
            if (!analysis.getUserId().equals(userId)) return forbiddenResponse();

            return ResponseEntity.ok(ApiResponse.success(analysis));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/my")
    public ResponseEntity<?> getUserAnalyses(
            @RequestHeader(value = "Authorization", required = false) String authHeader) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            return ResponseEntity.ok(ApiResponse.success(analysisService.getAllByUser(userId)));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/{analysisId}/history")
    public ResponseEntity<?> getAnalysisHistory(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String analysisId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingAnalysisV3Document> analysisOpt = analysisService.getAnalysisById(analysisId);
            if (analysisOpt.isEmpty()) return notFoundResponse("Анализ не найден");

            MarketingAnalysisV3Document analysis = analysisOpt.get();
            if (!analysis.getUserId().equals(userId)) return forbiddenResponse();

            AnalysisHistoryResponse response = new AnalysisHistoryResponse();
            response.setAnalysisId(analysis.getId());
            if (analysis.getRequestData() != null) {
                response.setBusinessNiche(analysis.getRequestData().getBusinessNiche());
                response.setProduct(analysis.getRequestData().getProductName());
                response.setGoal(analysis.getRequestData().getGoal());
                response.setDetailLevel(analysis.getRequestData().getDetailLevel());
                if (analysis.getRequestData().getAnalysisType() != null) {
                    response.setAnalysisType(String.join(", ", analysis.getRequestData().getAnalysisType()));
                }
                if (analysis.getRequestData().getClientTarget() != null) {
                    response.setTargetAudience(analysis.getRequestData().getClientTarget().name());
                }
                if (analysis.getRequestData().getPromotionCities() != null) {
                    response.setRegion(String.join(", ", analysis.getRequestData().getPromotionCities()));
                }
            }
            response.setStatus(analysis.getStatus());
            response.setUserId(analysis.getUserId());
            response.setCreatedAt(analysis.getCreatedAt());
            response.setCompletedAt(analysis.getUpdatedAt());

            return ResponseEntity.ok(ApiResponse.success(response));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/{analysisId}/download")
    public ResponseEntity<?> downloadPdf(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String analysisId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingAnalysisV3Document> analysisOpt = analysisService.getAnalysisById(analysisId);
            if (analysisOpt.isEmpty()) return ResponseEntity.notFound().build();

            MarketingAnalysisV3Document analysis = analysisOpt.get();
            if (!analysis.getUserId().equals(userId)) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
            }

            return ResponseEntity.notFound().build();
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    // =========================================================
    // MEDIA
    // =========================================================

    @GetMapping("/images/{imageFilename}")
    public ResponseEntity<byte[]> getPostImage(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String imageFilename) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();

        try {
            if (!minIOService.fileExists(imageFilename)) return ResponseEntity.notFound().build();

            InputStream is = minIOService.downloadFile(imageFilename);
            byte[] bytes   = is.readAllBytes();
            is.close();

            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE,  MediaType.IMAGE_PNG_VALUE)
                    .header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600")
                    .body(bytes);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @GetMapping("/videos/{videoFilename}")
    public ResponseEntity<Resource> getPostVideo(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String videoFilename) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();

        try {
            if (!minIOService.fileExists(videoFilename)) return ResponseEntity.notFound().build();

            InputStream is             = minIOService.downloadFile(videoFilename);
            InputStreamResource resource = new InputStreamResource(is);

            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE,  "video/mp4")
                    .header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600")
                    .body(resource);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    // =========================================================
    // STRATEGY — PREVIEW
    // Единственное место в контроллере, которое нужно было обновить:
    // старый calculateBestScoringModel(req) → новый calculateScoringModel(req, analysis),
    // который возвращает ScoringResult вместо StrategyModel.
    // Теперь preview показывает фронту и модель, и обоснование, и активные модификаторы.
    // =========================================================

    @GetMapping("/{analysisId}/strategy-preview")
    public ResponseEntity<?> previewStrategy(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String analysisId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingAnalysisV3Document> analysisOpt = analysisService.getAnalysisById(analysisId);
            if (analysisOpt.isEmpty()) return notFoundResponse("Анализ не найден");

            MarketingAnalysisV3Document analysis = analysisOpt.get();
            if (!analysis.getUserId().equals(userId)) return forbiddenResponse();

            // Используем новый метод: передаём и request, и analysis (для CII и рыночной интенсивности)
            ScoringResult scoring = strategyService.calculateScoringModel(
                    analysis.getRequestData(), analysis);

            Map<String, Object> responseData = new HashMap<>();
            responseData.put("recommendedModel",   scoring.getModel().name());
            responseData.put("modelTitle",          scoring.getModel().getTitle());
            responseData.put("rationale",           scoring.getRationale());
            responseData.put("activeModifiers",
                    scoring.getActiveModifiers().stream()
                            .map(m -> Map.of("key", m.name(), "title", m.getTitle()))
                            .collect(Collectors.toList()));
            responseData.put("scores", Map.of(
                    "entry",      scoring.getEntryScore(),
                    "authority",  scoring.getAuthorityScore(),
                    "trust",      scoring.getTrustScore(),
                    "conversion", scoring.getConversionScore()
            ));
            responseData.put("description",
                    "ИИ автоматически подберёт платформы и длительность контент-плана для этой стратегии.");

            return ResponseEntity.ok(ApiResponse.success("Рекомендация сформирована", responseData));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    // =========================================================
    // STRATEGY — GENERATE / GET
    // =========================================================

    @PostMapping(value = "/{analysisId}/strategy/generate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<?> generateStrategy(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String analysisId,
            @RequestPart(value = "request",    required = false) MarketingStrategyRequest request,
            @RequestPart(value = "references", required = false) List<MultipartFile> referenceFiles) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingAnalysisV3Document> analysisOpt = analysisService.getAnalysisById(analysisId);
            if (analysisOpt.isEmpty()) return notFoundResponse("Анализ не найден");
            if (!analysisOpt.get().getUserId().equals(userId)) return forbiddenResponse();

            // Загружаем референсные файлы (логотипы/стиль клиента) в MinIO
            List<String> savedReferenceFilenames = new ArrayList<>();
            if (referenceFiles != null && !referenceFiles.isEmpty()) {
                for (MultipartFile file : referenceFiles) {
                    if (!file.isEmpty()) {
                        String ext = (file.getOriginalFilename() != null
                                && file.getOriginalFilename().contains("."))
                                ? file.getOriginalFilename().substring(
                                file.getOriginalFilename().lastIndexOf("."))
                                : ".png";
                        String filename = "ref_" + UUID.randomUUID() + ext;
                        minIOService.uploadFile(filename, file.getBytes(), file.getContentType());
                        savedReferenceFilenames.add(filename);
                        log.info("Uploaded reference file: {}", filename);
                    }
                }
            }

            if (request == null) request = new MarketingStrategyRequest();

            MarketingStrategy strategy = strategyService.generateStrategy(
                    analysisId, request, userId, savedReferenceFilenames);

            return ResponseEntity.accepted().body(ApiResponse.success(
                    "Автономная генерация запущена",
                    Map.of(
                            "strategyId", strategy.getId(),
                            "status",     strategy.getStatus(),
                            "message",    "Генерация запущена. ИИ анализирует нишу для выбора лучших платформ."
                    )));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/strategy/{strategyId}")
    public ResponseEntity<?> getStrategyById(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String strategyId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingStrategy> strategyOpt = strategyService.getStrategyById(strategyId);
            if (strategyOpt.isEmpty()) return notFoundResponse("Стратегия не найдена");

            MarketingStrategy strategy = strategyOpt.get();
            if (!strategy.getUserId().equals(userId)) return forbiddenResponse();

            Map<String, Object> result = strategyService.getStrategyResult(strategyId);
            if (result == null) return notFoundResponse("Ошибка сборки стратегии");

            return ResponseEntity.ok(ApiResponse.success(result));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/{analysisId}/strategy")
    public ResponseEntity<?> getStrategyByAnalysis(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String analysisId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingAnalysisV3Document> optAnalysis = analysisService.getAnalysisById(analysisId);
            if (optAnalysis.isEmpty()) return notFoundResponse("Анализ не найден");
            if (!optAnalysis.get().getUserId().equals(userId)) return forbiddenResponse();

            Optional<MarketingStrategy> strategyOpt = strategyService.getStrategyByAnalysisId(analysisId);
            if (strategyOpt.isEmpty()) return notFoundResponse("Стратегия не найдена");

            Map<String, Object> result = strategyService.getStrategyResult(strategyOpt.get().getId());
            if (result == null) return notFoundResponse("Ошибка сборки стратегии");

            return ResponseEntity.ok(ApiResponse.success(result));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/strategy/my")
    public ResponseEntity<?> getMyStrategies(
            @RequestHeader(value = "Authorization", required = false) String authHeader) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            List<MarketingStrategy> strategies = strategyService.getUserStrategies(userId);
            List<StrategyHistoryResponse> responseList = strategies.stream()
                    .map(this::convertToStrategyHistoryResponse)
                    .collect(Collectors.toList());
            return ResponseEntity.ok(ApiResponse.success(responseList));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @GetMapping("/strategy/{strategyId}/history")
    public ResponseEntity<?> getStrategyHistory(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String strategyId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingStrategy> optStrategy = strategyService.getStrategyById(strategyId);
            if (optStrategy.isEmpty()) return notFoundResponse("Стратегия не найдена");

            MarketingStrategy strategy = optStrategy.get();
            if (!strategy.getUserId().equals(userId)) return forbiddenResponse();

            return ResponseEntity.ok(ApiResponse.success(convertToStrategyHistoryResponse(strategy)));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    // =========================================================
    // STRATEGY — START / TASKS
    // =========================================================

    @PostMapping("/strategy/{strategyId}/start")
    public ResponseEntity<?> startStrategy(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String strategyId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingStrategy> optStrategy = strategyService.getStrategyById(strategyId);
            if (optStrategy.isEmpty()) return notFoundResponse("Стратегия не найдена");

            MarketingStrategy strategy = optStrategy.get();
            if (!strategy.getUserId().equals(userId)) return forbiddenResponse();

            if (!"completed".equals(strategy.getStatus())) {
                return ResponseEntity.status(400).body(ApiResponse.error(
                        "Стратегия не готова к запуску",
                        new ErrorResponse("INVALID_STATUS",
                                "Стратегия ещё не завершена. Статус: " + strategy.getStatus())));
            }

            List<PostingTask> tasks  = postingTaskService.createTasksFromStrategy(strategyId);
            List<String> platforms   = tasks.stream()
                    .map(PostingTask::getPlatform).distinct().collect(Collectors.toList());

            return ResponseEntity.ok(ApiResponse.success(
                    "Стратегия успешно запущена",
                    new StartStrategyResponse(strategyId, tasks.size(), platforms,
                            "Стратегия запущена. Создано задач: " + tasks.size())));
        } catch (IllegalStateException e) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "Не удалось запустить стратегию",
                    new ErrorResponse("ERROR", e.getMessage())));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @PostMapping("/tasks/{taskId}/execute")
    public ResponseEntity<?> executeTaskManually(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String taskId) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<PostingTask> optTask = postingTaskService.getTaskById(taskId);
            if (optTask.isEmpty()) return notFoundResponse("Задача не найдена");

            PostingTask task = optTask.get();
            if (!userId.equals(task.getUserId())) return forbiddenResponse();

            postingTaskService.executeTaskManually(taskId);

            Optional<PostingTask> updated = postingTaskService.getTaskById(taskId);
            if (updated.isPresent()) {
                PostingTask t = updated.get();
                return ResponseEntity.ok(ApiResponse.success("Задача успешно запущена",
                        Map.of("taskId", t.getId(), "status", t.getStatus(),
                                "platform", t.getPlatform(), "publishDate", t.getPublishDate())));
            }

            return ResponseEntity.ok(ApiResponse.success("Задача отправлена в обработку",
                    Map.of("taskId", taskId)));
        } catch (IllegalStateException e) {
            return ResponseEntity.status(400).body(ApiResponse.error(
                    "Задача не может быть запущена",
                    new ErrorResponse("INVALID_STATUS", e.getMessage())));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    // =========================================================
    // STRATEGY — REGENERATE MEDIA
    // =========================================================

    @PostMapping("/strategy/{strategyId}/post/{postIndex}/regenerate-image")
    public ResponseEntity<?> regeneratePostImage(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String strategyId,
            @PathVariable int postIndex) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingStrategy> optStrategy = strategyService.getStrategyById(strategyId);
            if (optStrategy.isEmpty()) return notFoundResponse("Стратегия не найдена");
            if (!optStrategy.get().getUserId().equals(userId)) return forbiddenResponse();

            MarketingStrategy.PostCalendarItem updatedItem =
                    strategyService.regeneratePostImage(strategyId, postIndex);
            if (updatedItem == null) return notFoundResponse("Пост не найден");

            Map<String, Object> responseData = new HashMap<>();
            responseData.put("strategyId",    strategyId);
            responseData.put("postIndex",     postIndex);
            responseData.put("imageUrl",      updatedItem.getImageUrl()      != null ? updatedItem.getImageUrl()      : "");
            responseData.put("imageFilename", updatedItem.getImageFilename() != null ? updatedItem.getImageFilename() : "");
            responseData.put("videoUrl",      updatedItem.getVideoUrl()      != null ? updatedItem.getVideoUrl()      : "");
            responseData.put("videoFilename", updatedItem.getVideoFilename() != null ? updatedItem.getVideoFilename() : "");
            responseData.put("theme",         updatedItem.getTheme()         != null ? updatedItem.getTheme()         : "");
            responseData.put("platform",      updatedItem.getPlatform()      != null ? updatedItem.getPlatform()      : "");
            responseData.put("publishDate",   updatedItem.getPublishDate());

            return ResponseEntity.ok(ApiResponse.success("Изображение успешно регенерировано", responseData));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    @PostMapping("/strategy/{strategyId}/post/{postIndex}/regenerate-video")
    public ResponseEntity<?> regeneratePostVideo(
            @RequestHeader(value = "Authorization", required = false) String authHeader,
            @PathVariable String strategyId,
            @PathVariable int postIndex) {

        String userId = extractUserIdFromHeader(authHeader);
        if (userId == null) return unauthorizedResponse();

        try {
            Optional<MarketingStrategy> optStrategy = strategyService.getStrategyById(strategyId);
            if (optStrategy.isEmpty()) return notFoundResponse("Стратегия не найдена");
            if (!optStrategy.get().getUserId().equals(userId)) return forbiddenResponse();

            // Асинхронный вызов — сразу отдаём 202
            strategyService.regeneratePostVideoAsync(strategyId, postIndex);

            return ResponseEntity.accepted().body(ApiResponse.success(
                    "Генерация видео запущена",
                    Map.of("strategyId", strategyId,
                            "postIndex",  postIndex,
                            "message",    "Видео генерируется в фоновом режиме. Появится через несколько минут.")));
        } catch (Exception e) {
            return internalErrorResponse(e);
        }
    }

    // =========================================================
    // HELPERS
    // =========================================================

    private StrategyHistoryResponse convertToStrategyHistoryResponse(MarketingStrategy strategy) {
        StrategyHistoryResponse response = new StrategyHistoryResponse();
        response.setStrategyId(strategy.getId());
        response.setAnalysisId(strategy.getAnalysisId());
        response.setStatus(strategy.getStatus());
        response.setUserId(strategy.getUserId());
        response.setDurationWeeks(strategy.getDurationWeeks());
        response.setPriorityPlatforms(strategy.getPriorityPlatforms());

        // ── Название стратегической модели ───────────────────────────────────
        String modelName  = strategy.getScoringModelName();
        String modelTitle = strategy.getScoringModelTitle();
        // Резерв для старых записей (поля entity ещё не были, данные в strategyData)
        if (modelName == null && strategy.getStrategyData() != null) {
            Object v = strategy.getStrategyData().get("scoringModel");
            if (v != null) modelName = v.toString();
        }
        if (modelTitle == null && strategy.getStrategyData() != null) {
            Object v = strategy.getStrategyData().get("scoringModelTitle");
            if (v != null) modelTitle = v.toString();
        }
        response.setScoringModelName(modelName);
        response.setScoringModelTitle(modelTitle);

        // ── Название анализа для отображения в списках ───────────────────────
        // Формируем из данных связанного анализа: "Ниша — Продукт/Бренд"
        if (strategy.getAnalysisId() != null) {
            analysisService.getAnalysisById(strategy.getAnalysisId()).ifPresent(analysis -> {
                if (analysis.getRequestData() != null) {
                    String niche   = analysis.getRequestData().getBusinessNiche();
                    String product = analysis.getRequestData().getProductName();

                    String title;
                    if (niche != null && !niche.isBlank()
                            && product != null && !product.isBlank()) {
                        title = niche.trim() + " — " + product.trim();
                    } else if (niche != null && !niche.isBlank()) {
                        title = niche.trim();
                    } else if (product != null && !product.isBlank()) {
                        title = product.trim();
                    } else {
                        title = "Без названия";
                    }

                    // Обрезаем до 80 символов чтобы не ломать UI
                    if (title.length() > 80) {
                        title = title.substring(0, 77) + "...";
                    }
    
                    response.setAnalysisTitle(title);
                }
            });
        }
        // Если анализ не нашёлся — ставим заглушку
        if (response.getAnalysisTitle() == null) {
            response.setAnalysisTitle("Стратегия " + (strategy.getCreatedAt() != null
                    ? strategy.getCreatedAt().toLocalDate().toString()
                    : strategy.getId()));
        }
        // ─────────────────────────────────────────────────────────────────────

        response.setCreatedAt(strategy.getCreatedAt());
        response.setCompletedAt(strategy.getCompletedAt());
        response.setStatusHistory(strategy.getStatusHistory());
        return response;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResponse<ErrorResponse>> handleValidationException(
            MethodArgumentNotValidException ex) {
        Map<String, String> details = new HashMap<>();
        ex.getBindingResult().getFieldErrors()
                .forEach(e -> details.put(e.getField(), e.getDefaultMessage()));
        return ResponseEntity.badRequest().body(ApiResponse.error("Ошибка валидации",
                new ErrorResponse("VALIDATION_ERROR", "Ошибка валидации", details)));
    }

    private ResponseEntity<ApiResponse<Object>> unauthorizedResponse() {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ApiResponse.error(
                "Не авторизован",
                new ErrorResponse("UNAUTHORIZED", "Требуется авторизация. Предоставьте валидный JWT токен.")));
    }

    private ResponseEntity<ApiResponse<Object>> forbiddenResponse() {
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ApiResponse.error(
                "Доступ запрещён",
                new ErrorResponse("FORBIDDEN", "У вас нет прав для доступа к этому ресурсу.")));
    }

    private ResponseEntity<ApiResponse<Object>> notFoundResponse(String message) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.error(
                "Не найдено",
                new ErrorResponse("NOT_FOUND", message)));
    }

    private ResponseEntity<ApiResponse<Object>> internalErrorResponse(Exception e) {
        log.error("Internal error: {}", e.getMessage(), e);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ApiResponse.error(
                "Ошибка сервера",
                new ErrorResponse("INTERNAL_SERVER_ERROR", e.getMessage())));
    }
}