package com.dora.service.impl;

import com.dora.dto.ToolDto;
import com.dora.entity.ToolConfig;
import com.dora.entity.ToolUsageLog;
import com.dora.entity.User;
import com.dora.exception.BusinessException;
import com.dora.exception.InsufficientPointsException;
import com.dora.mapper.ToolConfigMapper;
import com.dora.mapper.ToolUsageLogMapper;
import com.dora.mapper.UserMapper;
import com.dora.service.PointsService;
import com.dora.service.ToolService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 工具服务实现类（用户端）
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ToolServiceImpl implements ToolService {

    private final ToolConfigMapper toolConfigMapper;
    private final ToolUsageLogMapper toolUsageLogMapper;
    private final UserMapper userMapper;
    private final PointsService pointsService;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    @Value("${tikhub.api.base-url:https://api.tikhub.io}")
    private String tikHubBaseUrl;

    @Value("${tikhub.api.key:}")
    private String tikHubApiKey;

    @Override
    public List<ToolDto.ToolListItem> getAvailableTools() {
        List<ToolConfig> configs = toolConfigMapper.selectAllEnabled();
        return configs.stream()
                .map(this::convertToListItem)
                .collect(Collectors.toList());
    }

    @Override
    public List<ToolDto.ToolListItem> getToolsByCategory(String category) {
        List<ToolConfig> configs = toolConfigMapper.selectByCategory(category);
        return configs.stream()
                .map(this::convertToListItem)
                .collect(Collectors.toList());
    }

    @Override
    public ToolDto.ToolListItem getToolDetail(String toolCode) {
        ToolConfig config = toolConfigMapper.selectByToolCode(toolCode);
        if (config == null) {
            throw new BusinessException("工具不存在: " + toolCode);
        }
        if (config.getIsEnabled() != 1) {
            throw new BusinessException("工具已禁用: " + toolCode);
        }
        return convertToListItem(config);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ToolDto.CallResponse callTool(Long userId, String toolCode, Map<String, Object> params, String clientIp) {
        long startTime = System.currentTimeMillis();
        String usageNo = generateUsageNo();
        
        // 1. 获取工具配置
        ToolConfig config = toolConfigMapper.selectByToolCode(toolCode);
        if (config == null) {
            throw new BusinessException("工具不存在: " + toolCode);
        }
        if (config.getIsEnabled() != 1) {
            throw new BusinessException("工具已禁用: " + toolCode);
        }

        // 2. 检查用户积分
        User user = userMapper.findById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        if (user.getPoints() < config.getPointsCost()) {
            throw new InsufficientPointsException("积分不足，需要 " + config.getPointsCost() + " 积分，当前余额 " + user.getPoints());
        }

        // 3. 扣除积分
        String description = "调用工具: " + config.getToolName();
        pointsService.deductPoints(userId, config.getPointsCost(), usageNo, description);

        // 4. 调用第三方API
        ToolUsageLog usageLog = new ToolUsageLog();
        usageLog.setUsageNo(usageNo);
        usageLog.setUserId(userId);
        usageLog.setToolId(config.getId());
        usageLog.setToolCode(toolCode);
        usageLog.setToolName(config.getToolName());
        usageLog.setPointsCost(config.getPointsCost());
        usageLog.setClientIp(clientIp);

        try {
            usageLog.setRequestParams(objectMapper.writeValueAsString(params));
        } catch (Exception e) {
            usageLog.setRequestParams("{}");
        }

        Object responseData = null;
        try {
            responseData = callTikHubApi(config, params);
            usageLog.setStatus("success");
            // 不保存响应数据到数据库
            usageLog.setResponseData(null);
        } catch (Exception e) {
            log.error("调用工具API失败: toolCode={}, error={}", toolCode, e.getMessage());
            usageLog.setStatus("failed");
            // 截断错误信息，避免超出数据库字段长度
            String errorMsg = e.getMessage();
            if (errorMsg != null && errorMsg.length() > 1000) {
                errorMsg = errorMsg.substring(0, 1000) + "...";
            }
            usageLog.setErrorMessage(errorMsg);
            
            // API调用失败，退还积分
            pointsService.refundPoints(userId, config.getPointsCost(), usageNo, "工具调用失败退款: " + config.getToolName());
            
            throw new BusinessException("工具调用失败: " + e.getMessage());
        } finally {
            usageLog.setRequestDuration(System.currentTimeMillis() - startTime);
            toolUsageLogMapper.insert(usageLog);
        }

        // 5. 获取最新积分余额
        User updatedUser = userMapper.findById(userId);

        return ToolDto.CallResponse.builder()
                .usageNo(usageNo)
                .pointsCost(config.getPointsCost())
                .remainingPoints(updatedUser.getPoints())
                .data(responseData)
                .build();
    }

    @Override
    public ToolDto.UsageLogPageResponse getUserUsageLogs(Long userId, Integer page, Integer size, String toolCode) {
        if (page == null || page < 1) page = 1;
        if (size == null || size < 1) size = 10;
        if (size > 100) size = 100;

        int offset = (page - 1) * size;

        List<ToolUsageLog> logs;
        Long total;

        if (toolCode != null && !toolCode.trim().isEmpty()) {
            logs = toolUsageLogMapper.selectByUserIdAndToolCode(userId, toolCode, offset, size);
            total = toolUsageLogMapper.countByUserId(userId); // 简化处理
        } else {
            logs = toolUsageLogMapper.selectByUserId(userId, offset, size);
            total = toolUsageLogMapper.countByUserId(userId);
        }

        List<ToolDto.UsageLogResponse> records = logs.stream()
                .map(this::convertToUsageLogResponse)
                .collect(Collectors.toList());

        return ToolDto.UsageLogPageResponse.builder()
                .records(records)
                .total(total)
                .page(page)
                .size(size)
                .build();
    }

    /**
     * 调用TikHub API
     */
    private Object callTikHubApi(ToolConfig config, Map<String, Object> params) {
        String url = tikHubBaseUrl + config.getApiEndpoint();
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setBearerAuth(tikHubApiKey);

        ResponseEntity<Map> response;
        
        if ("GET".equalsIgnoreCase(config.getRequestMethod())) {
            // GET请求，参数拼接到URL
            StringBuilder urlBuilder = new StringBuilder(url);
            if (params != null && !params.isEmpty()) {
                urlBuilder.append("?");
                params.forEach((key, value) -> {
                    urlBuilder.append(key).append("=").append(value).append("&");
                });
                url = urlBuilder.substring(0, urlBuilder.length() - 1);
            }
            HttpEntity<String> entity = new HttpEntity<>(headers);
            response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
        } else {
            // POST请求
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(params, headers);
            response = restTemplate.postForEntity(url, entity, Map.class);
        }

        if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
            Map body = response.getBody();
            // 检查TikHub API响应状态
            if (body.containsKey("code") && !Integer.valueOf(200).equals(body.get("code"))) {
                throw new BusinessException("API返回错误: " + body.get("message"));
            }
            return body.get("data");
        } else {
            throw new BusinessException("API请求失败: " + response.getStatusCode());
        }
    }

    private String generateUsageNo() {
        return "TU" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
    }

    private ToolDto.ToolListItem convertToListItem(ToolConfig config) {
        return ToolDto.ToolListItem.builder()
                .toolCode(config.getToolCode())
                .toolName(config.getToolName())
                .category(config.getCategory())
                .description(config.getDescription())
                .pointsCost(config.getPointsCost())
                .build();
    }

    private ToolDto.UsageLogResponse convertToUsageLogResponse(ToolUsageLog log) {
        return ToolDto.UsageLogResponse.builder()
                .usageNo(log.getUsageNo())
                .toolCode(log.getToolCode())
                .toolName(log.getToolName())
                .pointsCost(log.getPointsCost())
                .status(log.getStatus())
                .createTime(log.getCreateTime())
                .build();
    }
}
