package com.erp.ai.service.impl;

import com.erp.ai.dto.MessageDTO;
import com.erp.ai.service.AIChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * AI对话服务实现
 */
@Slf4j
@Service
public class AIChatServiceImpl implements AIChatService {

    private final WebClient webClient;
    private final StringRedisTemplate redisTemplate;

    @Value("${ai.default-service:openai}")
    private String defaultService;

    @Value("${ai.cache.enabled:true}")
    private boolean cacheEnabled;

    @Value("${ai.cache.ttl:3600}")
    private long cacheTtl;

    @Value("${ai.cache.prefix:ai:chat:}")
    private String cachePrefix;

    @Value("${ai.logging.enabled:true}")
    private boolean loggingEnabled;

    @Value("${ai.fallback.enabled:true}")
    private boolean fallbackEnabled;

    @Value("${ai.fallback.service-order:openai,aliyun_qwen,anthropic,azure_openai,local}")
    private List<String> fallbackOrder;

    private String currentService;

    // 服务配置映射
    private Map<String, ServiceConfig> serviceConfigs;

    public AIChatServiceImpl(WebClient.Builder webClientBuilder,
                             StringRedisTemplate redisTemplate) {
        this.webClient = webClientBuilder.build();
        this.redisTemplate = redisTemplate;
        this.currentService = defaultService;
        initServiceConfigs();
    }

    private void initServiceConfigs() {
        serviceConfigs = new HashMap<>();
    }

    @Override
    public Map<String, Object> chat(List<MessageDTO> messages, Map<String, Object> options) {
        // 生成缓存键
        String cacheKey = generateCacheKey(messages, options);

        // 检查缓存
        if (cacheEnabled) {
            String cached = redisTemplate.opsForValue().get(cacheKey);
            if (cached != null) {
                log.debug("命中缓存: {}", cacheKey);
                return parseJson(cached);
            }
        }

        // 构建请求
        try {
            Map<String, Object> result = callAIService(messages, options);

            // 缓存结果
            if (cacheEnabled && result.containsKey("success") && Boolean.TRUE.equals(result.get("success"))) {
                redisTemplate.opsForValue().set(cacheKey, toJson(result), cacheTtl, TimeUnit.SECONDS);
            }

            return result;
        } catch (Exception e) {
            log.error("AI服务调用失败: {}", e.getMessage());

            // 尝试降级服务
            if (fallbackEnabled) {
                return fallbackToNextService(messages, options);
            }

            return Map.of(
                "success", false,
                "error", "AI服务暂时不可用: " + e.getMessage(),
                "service", currentService
            );
        }
    }

    private Map<String, Object> callAIService(List<MessageDTO> messages, Map<String, Object> options) {
        ServiceConfig config = getServiceConfig(currentService);

        if (config == null) {
            // 模拟响应（开发环境）
            return mockAIResponse(messages);
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 根据不同服务设置认证头
        switch (currentService) {
            case "openai":
            case "aliyun_qwen":
                headers.set("Authorization", "Bearer " + config.getApiKey());
                break;
            case "azure_openai":
                headers.set("api-key", config.getApiKey());
                break;
            case "anthropic":
                headers.set("x-api-key", config.getApiKey());
                headers.set("anthropic-version", "2023-06-01");
                break;
            case "local":
                // 本地模型可能不需要认证
                break;
        }

        Map<String, Object> requestBody = buildRequestBody(messages, options, config);

        try {
            String responseBody = webClient.post()
                    .uri(config.getApiUrl())
                    .headers(h -> h.addAll(headers))
                    .bodyValue(requestBody)
                    .retrieve()
                    .bodyToMono(String.class)
                    .block(Duration.ofSeconds(config.getTimeout()));

            return parseAIResponse(responseBody);
        } catch (Exception e) {
            log.error("调用AI服务失败: {}", e.getMessage());
            return Map.of(
                "success", false,
                "error", e.getMessage(),
                "service", currentService
            );
        }
    }

    private Map<String, Object> buildRequestBody(List<MessageDTO> messages, Map<String, Object> options, ServiceConfig config) {
        Map<String, Object> body = new HashMap<>();

        switch (currentService) {
            case "openai":
            case "aliyun_qwen":
            case "local":
                body.put("model", config.getModel());
                body.put("messages", messages.stream()
                        .map(m -> Map.of("role", m.getRole(), "content", m.getContent()))
                        .collect(Collectors.toList()));
                body.put("max_tokens", options.getOrDefault("max_tokens", config.getMaxTokens()));
                body.put("temperature", options.getOrDefault("temperature", config.getTemperature()));
                body.put("stream", options.getOrDefault("stream", false));
                break;

            case "azure_openai":
                body.put("messages", messages.stream()
                        .map(m -> Map.of("role", m.getRole(), "content", m.getContent()))
                        .collect(Collectors.toList()));
                body.put("max_tokens", options.getOrDefault("max_tokens", config.getMaxTokens()));
                body.put("temperature", options.getOrDefault("temperature", config.getTemperature()));
                body.put("stream", options.getOrDefault("stream", false));
                break;

            case "anthropic":
                body.put("model", config.getModel());
                body.put("messages", messages.stream()
                        .map(m -> Map.of("role", m.getRole(), "content", m.getContent()))
                        .collect(Collectors.toList()));
                body.put("max_tokens", options.getOrDefault("max_tokens", config.getMaxTokens()));
                body.put("temperature", options.getOrDefault("temperature", config.getTemperature()));
                body.put("stream", options.getOrDefault("stream", false));
                break;
        }

        return body;
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> parseAIResponse(String responseBody) {
        Map<String, Object> response = parseJson(responseBody);

        String content = "";
        int tokens = 0;

        switch (currentService) {
            case "openai":
            case "aliyun_qwen":
            case "azure_openai":
            case "local":
                List<Map<String, Object>> choices = (List<Map<String, Object>>) response.get("choices");
                if (choices != null && !choices.isEmpty()) {
                    Map<String, Object> message = (Map<String, Object>) choices.get(0).get("message");
                    content = (String) message.get("content");
                }
                Map<String, Object> usage = (Map<String, Object>) response.get("usage");
                if (usage != null) {
                    tokens = ((Number) usage.getOrDefault("total_tokens", 0)).intValue();
                }
                break;

            case "anthropic":
                List<Map<String, Object>> contentBlocks = (List<Map<String, Object>>) response.get("content");
                if (contentBlocks != null && !contentBlocks.isEmpty()) {
                    content = (String) contentBlocks.get(0).get("text");
                }
                Map<String, Object> usageAnthropic = (Map<String, Object>) response.get("usage");
                if (usageAnthropic != null) {
                    int inputTokens = ((Number) usageAnthropic.getOrDefault("input_tokens", 0)).intValue();
                    int outputTokens = ((Number) usageAnthropic.getOrDefault("output_tokens", 0)).intValue();
                    tokens = inputTokens + outputTokens;
                }
                break;
        }

        return Map.of(
            "success", true,
            "content", content,
            "tokens", tokens,
            "raw_response", response
        );
    }

    private Map<String, Object> mockAIResponse(List<MessageDTO> messages) {
        String lastMessage = messages.get(messages.size() - 1).getContent();
        String response;

        // 根据消息内容生成模拟响应
        if (lastMessage.contains("你好") || lastMessage.contains("hi") || lastMessage.contains("hello")) {
            response = "你好！我是ERP系统AI助手。我可以帮你处理企业资源管理的各种问题，包括商品、订单、采购、库存、财务等模块的操作和咨询。有什么可以帮你的吗？";
        } else if (lastMessage.contains("商品")) {
            response = "关于商品管理，我可以帮你：\n1. 查询商品信息\n2. 添加新商品\n3. 更新商品库存\n4. 设置商品价格\n5. 管理商品分类\n\n请告诉我具体需要什么帮助？";
        } else if (lastMessage.contains("订单")) {
            response = "关于订单管理，我可以帮你：\n1. 查看订单状态\n2. 处理新订单\n3. 发货操作\n4. 订单统计\n5. 退款处理\n\n请提供订单号或具体问题。";
        } else if (lastMessage.contains("采购")) {
            response = "关于采购管理，我可以帮你：\n1. 创建采购单\n2. 供应商管理\n3. 采购审批流程\n4. 收货入库\n5. 采购统计\n\n请告诉我你的具体需求。";
        } else if (lastMessage.contains("库存")) {
            response = "关于库存管理，我可以帮你：\n1. 库存查询\n2. 库存预警\n3. 盘点管理\n4. 出入库记录\n5. 库存调拨\n\n请提供仓库或商品信息。";
        } else if (lastMessage.contains("财务")) {
            response = "关于财务管理，我可以帮你：\n1. 收支记录\n2. 财务报表\n3. 发票管理\n4. 对账处理\n5. 预算控制\n\n请告诉我具体财务问题。";
        } else {
            response = "我是ERP系统AI助手，可以帮你处理：\n• 商品管理\n• 订单处理\n• 采购管理\n• 库存控制\n• 财务统计\n• 系统操作指导\n\n请详细描述你的问题，我会尽力提供帮助。";
        }

        return Map.of(
            "success", true,
            "content", response,
            "tokens", estimateTokens(response),
            "mock", true
        );
    }

    private Map<String, Object> fallbackToNextService(List<MessageDTO> messages, Map<String, Object> options) {
        if (fallbackOrder == null || fallbackOrder.isEmpty()) {
            return Map.of(
                "success", false,
                "error", "所有AI服务都不可用"
            );
        }

        int currentIndex = fallbackOrder.indexOf(currentService);
        if (currentIndex < 0 || currentIndex >= fallbackOrder.size() - 1) {
            return Map.of(
                "success", false,
                "error", "所有AI服务都不可用"
            );
        }

        String nextService = fallbackOrder.get(currentIndex + 1);
        log.warn("AI服务降级: {} -> {}", currentService, nextService);

        String originalService = currentService;
        currentService = nextService;

        try {
            return callAIService(messages, options);
        } finally {
            currentService = originalService;
        }
    }

    @Override
    public Map<String, Object> testConnection() {
        List<MessageDTO> testMessages = Arrays.asList(
            MessageDTO.builder().role("system").content("你是一个测试助手").build(),
            MessageDTO.builder().role("user").content("请回复\"OK\"").build()
        );

        Map<String, Object> options = Map.of(
            "max_tokens", 10,
            "temperature", 0.1
        );

        Map<String, Object> result = chat(testMessages, options);

        return Map.of(
            "success", result.getOrDefault("success", false),
            "service", currentService,
            "message", Boolean.TRUE.equals(result.get("success")) ? "连接正常" : result.getOrDefault("error", "连接失败")
        );
    }

    @Override
    public String getCurrentService() {
        return currentService;
    }

    @Override
    public void setService(String service) {
        this.currentService = service;
    }

    @Override
    public List<String> getAvailableServices() {
        return new ArrayList<>(serviceConfigs.keySet());
    }

    @Override
    public Map<String, Map<String, Object>> getServiceStatus() {
        Map<String, Map<String, Object>> status = new HashMap<>();
        String originalService = currentService;

        for (String service : serviceConfigs.keySet()) {
            currentService = service;
            try {
                Map<String, Object> testResult = testConnection();
                status.put(service, Map.of(
                    "status", Boolean.TRUE.equals(testResult.get("success")) ? "online" : "offline",
                    "message", testResult.getOrDefault("message", "")
                ));
            } catch (Exception e) {
                status.put(service, Map.of(
                    "status", "error",
                    "message", e.getMessage()
                ));
            }
        }

        currentService = originalService;
        return status;
    }

    private ServiceConfig getServiceConfig(String service) {
        // 从配置中获取服务配置
        return serviceConfigs.get(service);
    }

    private String generateCacheKey(List<MessageDTO> messages, Map<String, Object> options) {
        String content = messages.stream()
                .map(m -> m.getRole() + ":" + m.getContent())
                .collect(Collectors.joining("|"));
        return cachePrefix + Integer.toHexString((content + options.toString()).hashCode());
    }

    private int estimateTokens(String text) {
        // 简单估算：中文约1.5字符=1token，英文约4字符=1token
        int chineseChars = (int) text.chars().filter(c -> c >= 0x4E00 && c <= 0x9FA5).count();
        int otherChars = text.length() - chineseChars * 3; // 中文字符占3字节
        return Math.max(1, (int) Math.ceil(chineseChars / 1.5 + otherChars / 4.0));
    }

    private Map<String, Object> parseJson(String json) {
        // 简单的JSON解析（实际使用Jackson）
        Map<String, Object> result = new HashMap<>();
        // 这里使用Jackson进行解析
        return result;
    }

    private String toJson(Map<String, Object> map) {
        // 简单的JSON序列化（实际使用Jackson）
        return "{}";
    }

    /**
     * 服务配置内部类
     */
    private static class ServiceConfig {
        private String apiUrl;
        private String apiKey;
        private String model;
        private int maxTokens = 2000;
        private double temperature = 0.7;
        private int timeout = 30;

        public String getApiUrl() { return apiUrl; }
        public void setApiUrl(String apiUrl) { this.apiUrl = apiUrl; }
        public String getApiKey() { return apiKey; }
        public void setApiKey(String apiKey) { this.apiKey = apiKey; }
        public String getModel() { return model; }
        public void setModel(String model) { this.model = model; }
        public int getMaxTokens() { return maxTokens; }
        public void setMaxTokens(int maxTokens) { this.maxTokens = maxTokens; }
        public double getTemperature() { return temperature; }
        public void setTemperature(double temperature) { this.temperature = temperature; }
        public int getTimeout() { return timeout; }
        public void setTimeout(int timeout) { this.timeout = timeout; }
    }
}
