package com.erp.ai.controller;

import com.erp.ai.client.LlmClient;
import com.erp.ai.client.LlmClientFactory;
import com.erp.ai.dto.ChatCompletionRequest;
import com.erp.ai.dto.GroupExecutionResult;
import com.erp.ai.exception.LlmClientException;
import com.erp.ai.model.AiAgentGroup;
import com.erp.ai.model.AiAgentUsageLog;
import com.erp.ai.service.AiAgentApiKeyService;
import com.erp.ai.service.AiAgentGroupService;
import com.erp.ai.service.AiAgentProviderService;
import com.erp.ai.service.AiAgentUsageService;
import com.erp.ai.service.MultiAgentExecutionEngine;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 외부 게이트웨이 (OpenAI 호환).
 * vexplor openClawProxyRoutes.ts 1:1 포팅.
 *
 * 인증: Epic D 의 ApiKeyAuthenticationFilter 가 sk-pipe-* 검증 후
 *      request attribute "ai_api_key_id" / "ai_api_key_user" 설정.
 *      필터 미설치 시: 헤더 fallback 처리 (개발 단계).
 */
@Slf4j
@RestController
@RequestMapping("/api/ai/v1")
@RequiredArgsConstructor
public class AiProxyController {

    private final LlmClientFactory llmClientFactory;
    private final MultiAgentExecutionEngine executionEngine;
    private final AiAgentGroupService groupService;
    private final AiAgentApiKeyService apiKeyService;
    private final AiAgentUsageService usageService;
    private final AiAgentProviderService providerService;

    /**
     * POST /api/ai/v1/chat/completions — OpenAI 호환 채팅.
     */
    @PostMapping("/chat/completions")
    public ResponseEntity<?> chatCompletions(@RequestBody ChatCompletionRequest req,
                                             HttpServletRequest httpRequest) {
        long startTime = System.currentTimeMillis();
        ApiKeyContext ctx = resolveApiKey(httpRequest);

        try {
            Map<String, Object> body = new HashMap<>();
            body.put("model", req.getModel());
            body.put("messages", req.getMessages());
            if (req.getMax_tokens() != null) body.put("max_tokens", req.getMax_tokens());
            if (req.getTemperature() != null) body.put("temperature", req.getTemperature());

            LlmClient client = llmClientFactory.pick(req.getModel());
            Map<String, Object> result = client.chat(body);

            // 사용량 추적
            Map<String, Object> usage = (Map<String, Object>) result.get("usage");
            int totalTokens = 0;
            int promptTokens = 0;
            int completionTokens = 0;
            if (usage != null) {
                if (usage.get("total_tokens") instanceof Number n) totalTokens = n.intValue();
                if (usage.get("prompt_tokens") instanceof Number n) promptTokens = n.intValue();
                if (usage.get("completion_tokens") instanceof Number n) completionTokens = n.intValue();
            }
            long elapsed = System.currentTimeMillis() - startTime;

            AiAgentUsageLog log = new AiAgentUsageLog();
            log.setUser_id(ctx.userId);
            log.setApi_key_id(ctx.keyId);
            log.setProvider_name(client.providerName());
            log.setModel_name(req.getModel());
            log.setPrompt_tokens(promptTokens);
            log.setCompletion_tokens(completionTokens);
            log.setTotal_tokens(totalTokens);
            log.setResponse_time_ms((int) elapsed);
            log.setSuccess(true);
            log.setRequest_path("/v1/chat/completions");
            log.setIp_address(httpRequest.getRemoteAddr());
            usageService.log(log);

            if (ctx.keyId != null && totalTokens > 0) {
                apiKeyService.addTokenUsage(ctx.keyId, totalTokens);
            }
            return ResponseEntity.ok(result);
        } catch (LlmClientException e) {
            long elapsed = System.currentTimeMillis() - startTime;
            AiAgentUsageLog log = new AiAgentUsageLog();
            log.setUser_id(ctx.userId);
            log.setApi_key_id(ctx.keyId);
            log.setModel_name(req.getModel());
            log.setResponse_time_ms((int) elapsed);
            log.setSuccess(false);
            log.setError_message(e.getMessage());
            log.setRequest_path("/v1/chat/completions");
            log.setIp_address(httpRequest.getRemoteAddr());
            usageService.log(log);

            return ResponseEntity.status(e.getStatusCode())
                    .body(Map.of("error", Map.of("message", e.getMessage(), "type", "server_error")));
        }
    }

    /**
     * POST /api/ai/v1/groups/{groupId} — 멀티 에이전트 그룹 실행.
     */
    @PostMapping("/groups/{groupId}")
    public ResponseEntity<?> executeGroup(@PathVariable String groupId,
                                          @RequestBody Map<String, Object> body,
                                          HttpServletRequest httpRequest) {
        ApiKeyContext ctx = resolveApiKey(httpRequest);
        Object messageObj = body.get("message");
        if (messageObj == null) {
            return ResponseEntity.badRequest().body(
                    Map.of("error", Map.of("message", "message is required", "type", "invalid_request")));
        }
        String message = String.valueOf(messageObj);

        long actualGroupId;
        try {
            actualGroupId = Long.parseLong(groupId);
        } catch (NumberFormatException e) {
            AiAgentGroup g = groupService.getByGroupId(groupId);
            if (g == null) {
                return ResponseEntity.status(404).body(
                        Map.of("error", Map.of("message", "Group not found", "type", "not_found")));
            }
            actualGroupId = g.getId();
        }

        try {
            GroupExecutionResult result = executionEngine.execute(actualGroupId, message, ctx.userId, ctx.keyId);
            Map<String, Object> data = new HashMap<>();
            data.put("group", result.getGroupName());
            data.put("execution_mode", result.getExecutionMode());
            data.put("total_tokens", result.getTotalTokens());
            data.put("duration_ms", result.getTotalDurationMs());
            data.put("steps", result.getSteps());
            data.put("summary", result.getFinalSummary());

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("data", data);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            return ResponseEntity.status(500).body(
                    Map.of("error", Map.of("message", e.getMessage(), "type", "execution_error")));
        }
    }

    /**
     * GET /api/ai/v1/groups — 사용 가능한 멀티 에이전트 그룹.
     */
    @GetMapping("/groups")
    public ResponseEntity<Map<String, Object>> listGroups() {
        List<AiAgentGroup> groups = groupService.list(null);
        Map<String, Object> resp = new HashMap<>();
        resp.put("success", true);
        resp.put("data", groups);
        return ResponseEntity.ok(resp);
    }

    /**
     * GET /api/ai/v1/models — 사용 가능한 모델 목록.
     */
    @GetMapping("/models")
    public ResponseEntity<Map<String, Object>> listModels() {
        List<Map<String, Object>> models = new ArrayList<>();
        try {
            providerService.getActiveProviders().forEach(p ->
                    models.add(Map.of(
                            "id", p.getModel_name(),
                            "object", "model",
                            "owned_by", p.getName())));
        } catch (Exception ignored) {
        }
        if (models.isEmpty()) {
            // fallback
            models.add(Map.of("id", "claude-sonnet-4-20250514", "object", "model", "owned_by", "anthropic"));
            models.add(Map.of("id", "gpt-4o", "object", "model", "owned_by", "openai"));
            models.add(Map.of("id", "gpt-4o-mini", "object", "model", "owned_by", "openai"));
        }
        Map<String, Object> resp = new HashMap<>();
        resp.put("object", "list");
        resp.put("data", models);
        return ResponseEntity.ok(resp);
    }

    /**
     * GET /api/ai/v1/health — AI 엔진 상태 확인.
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> health() {
        int activeProviders;
        try {
            activeProviders = providerService.getActiveProviders().size();
        } catch (Exception e) {
            activeProviders = 0;
        }
        Map<String, Object> resp = new HashMap<>();
        resp.put("status", activeProviders > 0 ? "running" : "no_providers");
        resp.put("engine", "invyone-native");
        resp.put("providers", activeProviders);
        return ResponseEntity.ok(resp);
    }

    /**
     * API key context 해석.
     * 1. ApiKeyAuthenticationFilter (Epic D) 가 설정한 attribute 우선
     * 2. fallback: Authorization 헤더 직접 파싱 + DB 검증
     */
    private ApiKeyContext resolveApiKey(HttpServletRequest request) {
        Long keyId = (Long) request.getAttribute("ai_api_key_id");
        String userId = (String) request.getAttribute("ai_api_key_user");
        if (keyId != null) {
            return new ApiKeyContext(keyId, userId);
        }

        // fallback: 직접 검증
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            String token = header.substring(7);
            if (token.startsWith("sk-pipe-")) {
                var key = apiKeyService.validateKey(token);
                if (key != null) {
                    return new ApiKeyContext(key.getId(), key.getUser_id());
                }
            }
        }
        // JWT 컨텍스트 fallback
        Object jwtUserId = request.getAttribute("user_id");
        return new ApiKeyContext(null, jwtUserId != null ? String.valueOf(jwtUserId) : null);
    }

    private record ApiKeyContext(Long keyId, String userId) {}
}
