package com.smyhub.infogenie.infogeniebackendjava.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.smyhub.infogenie.infogeniebackendjava.dto.request.AIToolRequest;
import com.smyhub.infogenie.infogeniebackendjava.dto.request.ChatRequest;
import com.smyhub.infogenie.infogeniebackendjava.dto.response.AIToolResponse;
import com.smyhub.infogenie.infogeniebackendjava.dto.response.ChatResponse;
import com.smyhub.infogenie.infogeniebackendjava.dto.response.ModelsResponse;
import com.smyhub.infogenie.infogeniebackendjava.filter.AuthCenterUser;
import com.smyhub.infogenie.infogeniebackendjava.service.AIModelService;
import com.smyhub.infogenie.infogeniebackendjava.service.AIToolService;
import com.smyhub.infogenie.infogeniebackendjava.util.AiResponseUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * AI model endpoints — requires a valid Bearer token on every request.
 *
 * POST /api/aimodelapp/chat
 * POST /api/aimodelapp/chat/stream  (SSE)
 * POST /api/aimodelapp/name-analysis
 * POST /api/aimodelapp/variable-naming
 * POST /api/aimodelapp/poetry
 * POST /api/aimodelapp/translation
 * POST /api/aimodelapp/classical_conversion
 * POST /api/aimodelapp/expression-maker
 * POST /api/aimodelapp/linux-command
 * POST /api/aimodelapp/markdown_formatting
 * POST /api/aimodelapp/kinship-calculator
 * GET  /api/aimodelapp/models
 */
@Slf4j
@RestController
@RequestMapping("/api/aimodelapp")
@RequiredArgsConstructor
public class AIModelController {

    private final AIModelService aiModelService;
    private final AIToolService aiToolService;
    private final AiResponseUtil aiResponseUtil;
    private final RestTemplate aiRestTemplate;
    private final ObjectMapper objectMapper;

    // ──────────────────────────── Auth guard ─────────────────────────────

    private boolean isAuthenticated(HttpServletRequest req) {
        return req.getAttribute(AuthCenterUser.AUTH_USER_ATTR) != null;
    }

    private ResponseEntity<Map<String, String>> unauthenticated() {
        return ResponseEntity.status(401).body(Map.of("error", "未授权，请先登录"));
    }

    // ──────────────────────────── Chat ───────────────────────────────────

    @PostMapping("/chat")
    public ResponseEntity<?> chat(@RequestBody ChatRequest req,
                                   HttpServletRequest httpReq) throws Exception {
        if (!isAuthenticated(httpReq)) return unauthenticated();

        List<Map<String, String>> messages = validateAndConvertMessages(req);
        if (messages == null) {
            return ResponseEntity.badRequest().body(Map.of("error", "消息列表无效或超出限制"));
        }

        String provider = req.getProvider() != null ? req.getProvider() : AIModelService.PROVIDER_DEEPSEEK;
        String model = req.getModel();

        String content = aiModelService.callAI(provider, model, messages);

        ChatResponse resp = new ChatResponse();
        resp.setContent(content);
        resp.setProvider(provider);
        resp.setModel(model != null ? model : AIModelService.DEFAULT_MODEL_DEEPSEEK);
        resp.setTimestamp(System.currentTimeMillis());
        return ResponseEntity.ok(resp);
    }

    @PostMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public void chatStream(@RequestBody ChatRequest req,
                           HttpServletRequest httpReq,
                           HttpServletResponse httpResp) throws Exception {
        if (!isAuthenticated(httpReq)) {
            httpResp.setStatus(401);
            return;
        }

        List<Map<String, String>> messages = validateAndConvertMessages(req);
        if (messages == null) {
            httpResp.setStatus(400);
            return;
        }

        String provider = req.getProvider() != null ? req.getProvider() : AIModelService.PROVIDER_DEEPSEEK;
        AIModelService.StreamConfig streamCfg =
                aiModelService.buildStreamConfig(provider, req.getModel(), messages);

        httpResp.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);
        httpResp.setCharacterEncoding("UTF-8");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setBearerAuth(streamCfg.apiKey());

        String bodyJson = objectMapper.writeValueAsString(streamCfg.body());

        RequestCallback requestCallback = clientHttpRequest -> {
            clientHttpRequest.getHeaders().addAll(headers);
            try (OutputStream os = clientHttpRequest.getBody()) {
                os.write(bodyJson.getBytes());
            }
        };

        try (PrintWriter writer = httpResp.getWriter()) {
            aiRestTemplate.execute(streamCfg.url(), HttpMethod.POST, requestCallback,
                    clientHttpResponse -> {
                        try (BufferedReader reader = new BufferedReader(
                                new InputStreamReader(clientHttpResponse.getBody()))) {
                            String line;
                            while ((line = reader.readLine()) != null) {
                                writer.write(line + "\n");
                                writer.flush();
                            }
                        }
                        return null;
                    });
        } catch (Exception e) {
            log.warn("Stream proxy error: {}", e.getMessage());
        }
    }

    // ──────────────────────────── Models ─────────────────────────────────

    @GetMapping("/models")
    public ResponseEntity<?> getModels(HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        ModelsResponse resp = new ModelsResponse();
        resp.setModels(aiModelService.getAllowedModels());
        resp.setDefaultProvider(AIModelService.PROVIDER_DEEPSEEK);
        resp.setDefaultModel(AIModelService.DEFAULT_MODEL_DEEPSEEK);
        return ResponseEntity.ok(resp);
    }

    // ──────────────────────────── AI Tools ───────────────────────────────

    @PostMapping("/name-analysis")
    public ResponseEntity<?> nameAnalysis(@RequestBody AIToolRequest req,
                                           HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.nameAnalysis(
                    aiResponseUtil.truncateInput(req.getInput()));
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("analysis", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/variable-naming")
    public ResponseEntity<?> variableNaming(@RequestBody AIToolRequest req,
                                             HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.variableNaming(
                    aiResponseUtil.truncateInput(req.getInput()), req.getLanguage());
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("suggestions", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/poetry")
    public ResponseEntity<?> poetry(@RequestBody AIToolRequest req,
                                     HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.poetry(
                    aiResponseUtil.truncateInput(req.getInput()), req.getStyle());
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("poem", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/translation")
    public ResponseEntity<?> translation(@RequestBody AIToolRequest req,
                                          HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.translation(
                    aiResponseUtil.truncateInput(req.getInput()),
                    req.getTargetLanguage(), req.getSourceLanguage());
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("translation", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/classical_conversion")
    public ResponseEntity<?> classicalConversion(@RequestBody AIToolRequest req,
                                                  HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.classicalConversion(
                    aiResponseUtil.truncateInput(req.getInput()));
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("result", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/expression-maker")
    public ResponseEntity<?> expressionMaker(@RequestBody AIToolRequest req,
                                              HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.expressionMaker(
                    aiResponseUtil.truncateInput(req.getInput()), req.getStyle());
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("expressions", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/linux-command")
    public ResponseEntity<?> linuxCommand(@RequestBody AIToolRequest req,
                                           HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.linuxCommand(
                    aiResponseUtil.truncateInput(req.getInput()));
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("command", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/markdown_formatting")
    public ResponseEntity<?> markdownFormatting(@RequestBody AIToolRequest req,
                                                 HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.markdownFormatting(
                    aiResponseUtil.truncateInput(req.getInput()));
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("markdown", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    @PostMapping("/kinship-calculator")
    public ResponseEntity<?> kinshipCalculator(@RequestBody AIToolRequest req,
                                                HttpServletRequest httpReq) {
        if (!isAuthenticated(httpReq)) return unauthenticated();
        try {
            String result = aiToolService.kinshipCalculator(
                    aiResponseUtil.truncateInput(req.getInput()));
            return ResponseEntity.ok(new AIToolResponse()
                    .addField("result", result)
                    .addField("timestamp", System.currentTimeMillis()));
        } catch (Exception e) {
            return toolError(e);
        }
    }

    // ──────────────────────────── Helpers ────────────────────────────────

    private List<Map<String, String>> validateAndConvertMessages(ChatRequest req) {
        if (req.getMessages() == null || req.getMessages().isEmpty()) return null;
        if (req.getMessages().size() > aiResponseUtil.getMaxChatMsgCount()) return null;
        return req.getMessages().stream()
                .map(m -> Map.of("role", m.getRole(), "content",
                        aiResponseUtil.truncateInput(m.getContent())))
                .collect(Collectors.toList());
    }

    private ResponseEntity<Map<String, String>> toolError(Exception e) {
        log.error("AI tool error: {}", e.getMessage());
        return ResponseEntity.status(500).body(Map.of("error", e.getMessage()));
    }
}
