package com.zioinfo.mall.ai.controller;

import com.zioinfo.mall.ai.learning.MallLearningStore;
import com.zioinfo.mall.common.ApiResponse;
import com.zioinfo.mall.rag.RagProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * AI 답변 피드백 수집 API — {@code POST /api/ai/feedback} (인증 사용자). [GUARDiA-MALL]
 *
 * <p>👍/👎(+교정)을 <b>둘 다</b> 기록한다:
 * <ol>
 *   <li>로컬 임베디드 DuckDB({@link MallLearningStore#recordFeedback}) — 솔루션별 오프라인 학습셋(PII 마스킹).</li>
 *   <li>중앙 guardia-rag 학습 서비스({@code {rag.base-url}/feedback}, 온프레미스 루프백) — 통합 학습·평가 게이트.</li>
 * </ol>
 *
 * <p><b>불변</b>: 중앙 전달 실패는 예외 미전파(로컬 기록은 유지). 응답에 키·PII·스택트레이스 미노출.
 * 외부 호출 금지 — 중앙 rag 는 서버 내부 루프백(127.0.0.1:8020)이다.
 */
@Slf4j
@RestController
@RequestMapping("/api/ai/feedback")
@RequiredArgsConstructor
public class AiFeedbackController {

    private final MallLearningStore learningStore;
    private final WebClient.Builder webClientBuilder;
    private final RagProperties ragProps;

    @PostMapping
    public ApiResponse<Map<String, Object>> feedback(@RequestBody Map<String, Object> req, Authentication auth) {
        String feature = str(req.get("feature"));
        String question = str(req.get("question"));
        String answer = str(req.get("answer"));
        String verdict = normVerdict(str(req.get("verdict")));
        String correction = str(req.get("correction"));
        String userRef = auth != null ? auth.getName() : null;

        // 1) 로컬 DuckDB 기록(PII 마스킹, 내결함성)
        learningStore.recordFeedback(feature, question, answer, verdict, correction, userRef);

        // 2) 중앙 guardia-rag 전달(온프레미스 루프백, 실패해도 무시)
        boolean forwarded = forwardCentral(feature, question, answer, verdict, correction, userRef);

        Map<String, Object> out = new LinkedHashMap<>();
        out.put("storedLocal", learningStore.isEnabled());
        out.put("forwardedCentral", forwarded);
        out.put("verdict", verdict);
        return ApiResponse.ok(out);
    }

    /** POST {rag.base-url}/feedback — solution=mall 격리. 실패 시 false(예외 미전파). */
    @SuppressWarnings("unchecked")
    private boolean forwardCentral(String feature, String question, String answer,
                                   String verdict, String correction, String userRef) {
        if (!ragProps.isEnabled()) return false;
        try {
            Map<String, Object> body = new LinkedHashMap<>();
            body.put("solution", ragProps.getSolution());
            if (feature != null) body.put("feature", feature);
            if (question != null) body.put("question", question);
            if (answer != null) body.put("answer", answer);
            body.put("verdict", verdict);
            if (correction != null) body.put("correction", correction);
            if (userRef != null) body.put("user_ref", userRef);
            Map<String, Object> res = webClientBuilder.baseUrl(ragProps.getBaseUrl()).build()
                    .post().uri("/feedback")
                    .header("X-Solution-Key", ragProps.getSolution())
                    .bodyValue(body)
                    .retrieve()
                    .bodyToMono(Map.class)
                    .timeout(Duration.ofMillis(Math.min(ragProps.getTimeoutMs(), 10_000L)))
                    .map(m -> (Map<String, Object>) m)
                    .block();
            return res != null;
        } catch (Exception e) {
            log.warn("중앙 rag /feedback 전달 실패(무시): {}", e.getClass().getSimpleName());
            return false;
        }
    }

    private static String str(Object o) {
        if (o == null) return null;
        String s = String.valueOf(o).trim();
        return s.isEmpty() ? null : s;
    }

    /** verdict 정규화: up/down 만 허용(그 외는 'down' 로 보수적 처리). */
    private static String normVerdict(String v) {
        if (v == null) return "down";
        String l = v.toLowerCase();
        if (l.startsWith("up") || l.equals("good") || l.equals("👍") || l.equals("positive")) return "up";
        return "down";
    }
}
