package com.erp.warehouse.client.wdt;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.erp.warehouse.client.CloudWmsClient;
import com.erp.warehouse.client.CloudWmsClientFactory.CloudWmsConfig;
import com.erp.warehouse.dto.PurchaseOrderDTO;
import com.erp.warehouse.dto.SaleOrderDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.Duration;
import java.util.*;

/**
 * 旺店通WMS客户端
 * 文档: https://open.wdtms.com/
 */
@Slf4j
@Component
public class WdtClient implements CloudWmsClient {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WdtClient.class);
    private static final String CACHE_KEY_PREFIX = "wdt_access_token_";
    private static final Duration TOKEN_EXPIRE = Duration.ofHours(2);

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RestTemplate restTemplate;

    private CloudWmsConfig config;

    public WdtClient withConfig(CloudWmsConfig config) {
        this.config = config;
        return this;
    }

    @Override
    public Object testConnection() {
        return request("wdt.shop.list.get", Map.of("page_no", 1, "page_size", 10));
    }

    @Override
    public Object getGoodsList(int page, int pageSize) {
        Map<String, Object> params = new HashMap<>();
        params.put("page_no", page);
        params.put("page_size", pageSize);
        return request("wdt.item.list.get", params);
    }

    @Override
    public Object getGoodsDetail(String goodsId) {
        return request("wdt.item.get", Map.of("goods_id", goodsId));
    }

    @Override
    public Object getStockList(String warehouseCode, int page, int pageSize) {
        Map<String, Object> params = new HashMap<>();
        params.put("page_no", page);
        params.put("page_size", pageSize);
        params.put("warehouse_no", warehouseCode);
        return request("wdt.stock.list.get", params);
    }

    @Override
    public Object queryStock(String skuCode, String warehouseCode) {
        Map<String, Object> params = new HashMap<>();
        params.put("spec_no", skuCode);
        if (warehouseCode != null && !warehouseCode.isEmpty()) {
            params.put("warehouse_no", warehouseCode);
        }
        return request("wdt.stock.detail.get", params);
    }

    @Override
    public CloudWmsResponse pushPurchaseOrder(PurchaseOrderDTO purchaseOrder) {
        Map<String, Object> order = new HashMap<>();
        order.put("po_no", purchaseOrder.getPoOrderNo());
        order.put("supplier_no", purchaseOrder.getSupplierCode());
        order.put("warehouse_no", purchaseOrder.getWarehouseCode());
        order.put("plan_arrive_date", purchaseOrder.getExpectedDate() != null ? 
                purchaseOrder.getExpectedDate().toString() : java.time.LocalDate.now().toString());
        order.put("remark", purchaseOrder.getRemark());

        List<Map<String, Object>> items = new ArrayList<>();
        if (purchaseOrder.getItems() != null) {
            for (PurchaseOrderDTO.PurchaseOrderItemDTO item : purchaseOrder.getItems()) {
                Map<String, Object> detail = new HashMap<>();
                detail.put("spec_no", item.getSkuCode());
                detail.put("name", item.getName());
                detail.put("num", item.getQuantity());
                detail.put("price", item.getPrice());
                items.add(detail);
            }
        }
        order.put("items", items);

        return requestResponse("wdt.purchase.order.create", order);
    }

    @Override
    public CloudWmsResponse confirmPurchaseOrder(String poNo) {
        Map<String, Object> params = Map.of("po_no", poNo);
        return requestResponse("wdt.purchase.order.confirm", params);
    }

    @Override
    public CloudWmsResponse pushSaleOrder(SaleOrderDTO saleOrder) {
        Map<String, Object> order = new HashMap<>();
        order.put("shop_no", saleOrder.getShopNo());
        order.put("warehouse_no", saleOrder.getWarehouseCode());
        order.put("receiver_name", saleOrder.getReceiverName());
        order.put("receiver_tel", saleOrder.getReceiverPhone());
        order.put("receiver_province", saleOrder.getReceiverProvince());
        order.put("receiver_city", saleOrder.getReceiverCity());
        order.put("receiver_district", saleOrder.getReceiverDistrict());
        order.put("receiver_address", saleOrder.getReceiverAddress());
        order.put("logistics_no", saleOrder.getLogisticsNo());
        order.put("remark", saleOrder.getRemark());

        List<Map<String, Object>> goodsList = new ArrayList<>();
        if (saleOrder.getItems() != null) {
            for (SaleOrderDTO.SaleOrderItemDTO item : saleOrder.getItems()) {
                Map<String, Object> detail = new HashMap<>();
                detail.put("spec_no", item.getSkuCode());
                detail.put("name", item.getName());
                detail.put("num", item.getQuantity());
                detail.put("price", item.getPrice());
                goodsList.add(detail);
            }
        }
        order.put("goods_list", goodsList);

        return requestResponse("wdt.trade.order.create", order);
    }

    @Override
    public Object getLogisticsTrace(String logisticsNo) {
        return request("wdt.logistics.trace.get", Map.of("logistics_no", logisticsNo));
    }

    @Override
    public CloudWmsResponse adjustStock(String warehouseCode, String skuCode, int type, int quantity, String reason) {
        Map<String, Object> params = new HashMap<>();
        params.put("warehouse_no", warehouseCode);
        params.put("spec_no", skuCode);
        params.put("type", type);
        params.put("num", quantity);
        params.put("reason", reason);
        return requestResponse("wdt.stock.adjust", params);
    }

    @Override
    public Object getWarehouseList() {
        return request("wdt.warehouse.list.get", Map.of());
    }

    /**
     * 发送API请求
     */
    private Object request(String method, Map<String, Object> params) {
        String accessToken = getAccessToken();
        
        Map<String, Object> requestParams = new HashMap<>(params);
        requestParams.put("app_key", config.getAppKey());
        requestParams.put("access_token", accessToken);
        requestParams.put("method", method);
        requestParams.put("timestamp", java.time.LocalDateTime.now().format(
                java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        requestParams.put("format", "json");
        requestParams.put("v", "2.0");
        
        // 生成签名
        requestParams.put("sign", generateSign(requestParams));

        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestParams, headers);
            ResponseEntity<String> response = restTemplate.exchange(
                    config.getApiUrl() + "/openapi/router",
                    HttpMethod.POST,
                    entity,
                    String.class
            );

            JSONObject result = JSON.parseObject(response.getBody());
            
            if (result == null) {
                return CloudWmsResponse.error(-1, "请求失败: 响应为空");
            }

            Integer code = result.getInteger("code");
            if (code != null && code != 0) {
                log.warn("WDT API错误: method={}, code={}, message={}", 
                        method, code, result.getString("message"));
                return CloudWmsResponse.error(code, result.getString("message"));
            }

            return CloudWmsResponse.success(result.get("data"));

        } catch (Exception e) {
            log.error("WDT请求异常: method={}, error={}", method, e.getMessage(), e);
            return CloudWmsResponse.error(-1, e.getMessage());
        }
    }

    /**
     * 发送API请求并返回CloudWmsResponse
     */
    private CloudWmsResponse requestResponse(String method, Map<String, Object> params) {
        Object result = request(method, params);
        if (result instanceof CloudWmsResponse) {
            return (CloudWmsResponse) result;
        }
        return CloudWmsResponse.error(-1, "未知错误");
    }

    /**
     * 获取访问令牌
     */
    private String getAccessToken() {
        String cacheKey = CACHE_KEY_PREFIX + md5(config.getAppKey());
        
        String cachedToken = redisTemplate.opsForValue().get(cacheKey);
        if (cachedToken != null && !cachedToken.isEmpty()) {
            return cachedToken;
        }

        try {
            Map<String, Object> params = new HashMap<>();
            params.put("app_key", config.getAppKey());
            params.put("app_secret", config.getAppSecret());
            params.put("grant_type", "client_credentials");

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(params, headers);
            ResponseEntity<String> response = restTemplate.exchange(
                    config.getApiUrl() + "/oauth/token",
                    HttpMethod.POST,
                    entity,
                    String.class
            );

            JSONObject result = JSON.parseObject(response.getBody());
            String accessToken = result.getString("access_token");

            if (accessToken != null && !accessToken.isEmpty()) {
                redisTemplate.opsForValue().set(cacheKey, accessToken, TOKEN_EXPIRE);
                return accessToken;
            }

            throw new RuntimeException("获取旺店通访问令牌失败");

        } catch (Exception e) {
            log.error("获取旺店通访问令牌异常: {}", e.getMessage(), e);
            throw new RuntimeException("获取旺店通访问令牌失败: " + e.getMessage());
        }
    }

    /**
     * 生成签名
     */
    private String generateSign(Map<String, Object> params) {
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);

        StringBuilder signString = new StringBuilder();
        for (String key : keys) {
            Object value = params.get(key);
            if (value != null && !value.toString().isEmpty() && !"sign".equals(key)) {
                signString.append(key).append(value.toString());
            }
        }
        
        String sign = signString.toString() + config.getAppSecret();
        return md5(sign).toUpperCase();
    }

    private String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException("MD5计算失败", e);
        }
    }
}
