package com.erp.platformsync.adapter;

import com.erp.platformsync.dto.PullOrdersResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import jakarta.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 平台适配器工厂 - 根据平台编码返回对应的适配器实例
 * 实现真正的HTTP调用，支持重试和Redis token缓存
 */
@Slf4j
@Component
public class PlatformAdapterFactory {

    // ==================== 常量定义 ====================
    private static final DateTimeFormatter DT_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
    private static final String REDIS_TOKEN_KEY_PREFIX = "erp:platform:token:";
    private static final Duration TOKEN_CACHE_TTL = Duration.ofHours(1);

    // ==================== Redis Token缓存服务 ====================
    @Slf4j
    public static class PlatformTokenService {
        private final StringRedisTemplate redisTemplate;

        public PlatformTokenService(StringRedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
        }

        public String getToken(String platformCode) {
            try {
                String key = REDIS_TOKEN_KEY_PREFIX + platformCode;
                return redisTemplate.opsForValue().get(key);
            } catch (Exception e) {
                log.warn("[{}] 获取Redis缓存token失败: {}", platformCode, e.getMessage());
                return null;
            }
        }

        public void saveToken(String platformCode, String token) {
            try {
                String key = REDIS_TOKEN_KEY_PREFIX + platformCode;
                redisTemplate.opsForValue().set(key, token, TOKEN_CACHE_TTL);
                log.debug("[{}] token已缓存到Redis", platformCode);
            } catch (Exception e) {
                log.warn("[{}] 保存token到Redis失败: {}", platformCode, e.getMessage());
            }
        }

        public void removeToken(String platformCode) {
            try {
                String key = REDIS_TOKEN_KEY_PREFIX + platformCode;
                redisTemplate.delete(key);
            } catch (Exception e) {
                log.warn("[{}] 删除Redis token失败: {}", platformCode, e.getMessage());
            }
        }
    }

    // ==================== 平台适配器基类 ====================
    private abstract static class BaseAdapter implements PlatformAdapter {
        protected final RestTemplate restTemplate;
        protected final PlatformTokenService tokenService;
        protected final ObjectMapper objectMapper;

        protected BaseAdapter(RestTemplate restTemplate, PlatformTokenService tokenService) {
            this.restTemplate = restTemplate;
            this.tokenService = tokenService;
            this.objectMapper = new ObjectMapper();
            this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        }

        protected String formatTime(LocalDateTime time) {
            if (time == null) return null;
            return time.format(DT_FORMATTER);
        }

        protected String currentTimestamp() {
            return String.valueOf(System.currentTimeMillis() / 1000);
        }

        protected String md5Sign(String data) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] hash = md.digest(data.getBytes(StandardCharsets.UTF_8));
                StringBuilder sb = new StringBuilder();
                for (byte b : hash) {
                    sb.append(String.format("%02x", b));
                }
                return sb.toString().toUpperCase();
            } catch (NoSuchAlgorithmException e) {
                return null;
            }
        }

        protected String buildQueryUrl(String baseUrl, Map<String, ?> params) {
            if (params == null || params.isEmpty()) return baseUrl;
            StringBuilder sb = new StringBuilder(baseUrl);
            sb.append(baseUrl.contains("?") ? "&" : "?");
            params.forEach((key, value) -> {
                if (value != null) {
                    sb.append(key).append("=").append(value.toString()).append("&");
                }
            });
            return sb.toString().replaceAll("&$", "");
        }

        @Retryable(
            retryFor = { RestClientException.class, HttpServerErrorException.class },
            maxAttempts = 3,
            backoff = @Backoff(delay = 1000, multiplier = 2)
        )
        protected <T> T doPost(String url, HttpHeaders headers, Object body, Class<T> responseType) {
            try {
                HttpEntity<Object> entity = new HttpEntity<>(body, headers);
                log.debug("[{}] HTTP POST: {}", getPlatformCode(), url);
                ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.POST, entity, responseType);
                return response.getBody();
            } catch (HttpClientErrorException e) {
                log.error("[{}] HTTP 客户端错误: status={}, body={}", getPlatformCode(), e.getStatusCode(), e.getResponseBodyAsString());
                throw e;
            } catch (HttpServerErrorException e) {
                log.error("[{}] HTTP 服务端错误: status={}, body={}", getPlatformCode(), e.getStatusCode(), e.getResponseBodyAsString());
                throw e;
            } catch (RestClientException e) {
                log.error("[{}] HTTP 请求失败: {}", getPlatformCode(), e.getMessage());
                throw e;
            }
        }

        protected PullOrdersResponse httpCallAndParse(String url, HttpHeaders headers, Object body) {
            try {
                HttpEntity<Object> entity = new HttpEntity<>(body, headers);
                log.debug("[{}] HTTP POST: {}", getPlatformCode(), url);
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
                String json = response.getBody();
                log.debug("[{}] 响应: {}", getPlatformCode(), json);
                if (json == null || json.isEmpty()) {
                    return PullOrdersResponse.builder().orders(Collections.emptyList()).total(0).build();
                }
                return objectMapper.readValue(json, PullOrdersResponse.class);
            } catch (JsonProcessingException e) {
                log.error("[{}] JSON解析失败: {}", getPlatformCode(), e.getMessage());
                return PullOrdersResponse.builder().orders(Collections.emptyList()).total(0).build();
            } catch (RestClientException e) {
                log.error("[{}] HTTP请求失败: {}", getPlatformCode(), e.getMessage());
                return PullOrdersResponse.builder().orders(Collections.emptyList()).total(0).build();
            }
        }

        protected boolean httpSyncCall(String url, HttpHeaders headers, Object body) {
            try {
                HttpEntity<Object> entity = new HttpEntity<>(body, headers);
                log.debug("[{}] HTTP POST 同步: {}", getPlatformCode(), url);
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
                String json = response.getBody();
                log.debug("[{}] 同步响应: {}", getPlatformCode(), json);
                return parseSyncResponse(json);
            } catch (RestClientException e) {
                log.error("[{}] 同步HTTP请求失败: {}", getPlatformCode(), e.getMessage());
                return false;
            }
        }

        protected boolean parseSyncResponse(String json) {
            if (json == null || json.isEmpty()) return false;
            try {
                Map<String, Object> map = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
                // 通用解析：检查是否有error字段或success=false
                if (map.containsKey("error_response")) {
                    Map<String, Object> error = (Map<String, Object>) map.get("error_response");
                    log.warn("[{}] 同步失败: code={}, msg={}", getPlatformCode(), error.get("code"), error.get("sub_msg"));
                    return false;
                }
                if (map.containsKey("error")) {
                    log.warn("[{}] 同步失败: {}", getPlatformCode(), map.get("error"));
                    return false;
                }
                return true;
            } catch (JsonProcessingException e) {
                log.warn("[{}] 无法解析同步响应: {}", getPlatformCode(), json);
                return false;
            }
        }
    }

    // ==================== 淘宝/天猫适配器 ====================
    @Slf4j
    public static class TaobaoAdapter extends BaseAdapter {
        private final String apiUrl;
        private final String appKey;
        private final String appSecret;

        public TaobaoAdapter(RestTemplate restTemplate, PlatformTokenService tokenService,
                           String apiUrl, String appKey, String appSecret) {
            super(restTemplate, tokenService);
            this.apiUrl = apiUrl != null && !apiUrl.isEmpty() ? apiUrl : "https://eco.taobao.com/router/rest";
            this.appKey = appKey;
            this.appSecret = appSecret;
        }

        @Override
        public String getPlatformCode() { return "taobao"; }
        @Override
        public String getPlatformName() { return "淘宝/天猫"; }

        @Override
        public boolean isConfigured() {
            return apiUrl != null && !apiUrl.isEmpty() && appKey != null && !appKey.isEmpty()
                    && appSecret != null && !appSecret.isEmpty();
        }

        @Override
        public List<PullOrdersResponse.PullOrderItem> pullOrders(Long shopId, String pullType,
                                                                  String orderIds, LocalDateTime startTime,
                                                                  LocalDateTime endTime) {
            if (!isConfigured()) {
                log.warn("[taobao] 平台未配置，跳过拉取");
                return Collections.emptyList();
            }

            try {
                // 获取缓存的token或使用配置token
                String token = tokenService.getToken("taobao");
                if (token == null) {
                    token = "";
                }

                Map<String, Object> params = new LinkedHashMap<>();
                params.put("method", "taobao.trades.sold.get");
                params.put("app_key", appKey);
                params.put("timestamp", formatTime(LocalDateTime.now()));
                params.put("format", "json");
                params.put("v", "2.0");
                params.put("sign_method", "md5");
                params.put("session", token);
                params.put("type", "guarantee_trade");
                params.put("page_size", 100);
                if (startTime != null) params.put("start_created", formatTime(startTime));
                if (endTime != null) params.put("end_created", formatTime(endTime));

                String fields = "tid,status,orders,buyer_nick,receiver_name,receiver_phone," +
                        "receiver_address,total_fee,post_fee,payment,created,pay_time,consign_time," +
                        "shipping_type,logistics_company";
                params.put("fields", fields);

                String sign = generateSign(params);
                params.put("sign", sign);

                String fullUrl = buildQueryUrl(apiUrl, params);
                log.info("[taobao] 拉取订单: url={}, shopId={}, pullType={}, startTime={}", 
                        apiUrl, shopId, pullType, startTime);

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

                PullOrdersResponse resp = httpCallAndParse(fullUrl, headers, null);
                if (resp != null && resp.getOrders() != null) {
                    log.info("[taobao] 拉取成功: count={}", resp.getOrders().size());
                    return resp.getOrders();
                }

                // 尝试解析淘宝TOP API响应格式
                return parseTaobaoTradesResponse(fullUrl, headers);

            } catch (Exception e) {
                log.error("[taobao] 拉取订单异常: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        private List<PullOrdersResponse.PullOrderItem> parseTaobaoTradesResponse(String url, HttpHeaders headers) {
            try {
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(headers), String.class);
                String json = response.getBody();
                if (json == null || json.isEmpty()) return Collections.emptyList();

                Map<String, Object> root = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
                String tradeKey = "trades_sold_get_response";
                if (!root.containsKey(tradeKey)) {
                    log.debug("[taobao] 响应中无trades_sold_get_response: {}", json);
                    return Collections.emptyList();
                }

                Map<String, Object> resp = (Map<String, Object>) root.get(tradeKey);
                Object tradesObj = resp.get("trades");
                if (tradesObj == null) return Collections.emptyList();

                List<Map<String, Object>> trades = (List<Map<String, Object>>) tradesObj;
                List<PullOrdersResponse.PullOrderItem> orders = new ArrayList<>();

                for (Map<String, Object> trade : trades) {
                    PullOrdersResponse.PullOrderItem item = PullOrdersResponse.PullOrderItem.builder()
                            .orderSn(String.valueOf(trade.get("tid")))
                            .platformOrderSn(String.valueOf(trade.get("tid")))
                            .platform("taobao")
                            .status(String.valueOf(trade.get("status")))
                            .receiverName(String.valueOf(trade.get("receiver_name")))
                            .receiverPhone(String.valueOf(trade.get("receiver_phone")))
                            .receiverAddress(String.valueOf(trade.get("receiver_address")))
                            .createdTime(String.valueOf(trade.get("created")))
                            .payTime(String.valueOf(trade.get("pay_time")))
                            .totalAmount(trade.get("payment") != null ? 
                                    new java.math.BigDecimal(trade.get("payment").toString()) : java.math.BigDecimal.ZERO)
                            .build();
                    orders.add(item);
                }

                log.info("[taobao] 解析订单成功: count={}", orders.size());
                return orders;
            } catch (Exception e) {
                log.error("[taobao] 解析淘宝订单响应失败: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        @Override
        public boolean syncOrderToPlatform(String platformOrderSn, String syncStatus,
                                           String expressCompany, String expressNo) {
            if (!isConfigured()) {
                log.warn("[taobao] 平台未配置，跳过同步");
                return false;
            }

            try {
                String token = tokenService.getToken("taobao");
                if (token == null) token = "";

                Map<String, Object> params = new LinkedHashMap<>();
                params.put("method", "taobao.logistics.online.send");
                params.put("app_key", appKey);
                params.put("timestamp", formatTime(LocalDateTime.now()));
                params.put("format", "json");
                params.put("v", "2.0");
                params.put("sign_method", "md5");
                params.put("session", token);
                params.put("tid", platformOrderSn);
                if (expressCompany != null) params.put("company_code", expressCompany);
                if (expressNo != null) params.put("out_sid", expressNo);

                String sign = generateSign(params);
                params.put("sign", sign);

                String fullUrl = buildQueryUrl(apiUrl, params);
                log.info("[taobao] 同步订单发货: url={}, tid={}, company={}, outSid={}",
                        apiUrl, platformOrderSn, expressCompany, expressNo);

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

                return httpSyncCall(fullUrl, headers, null);

            } catch (Exception e) {
                log.error("[taobao] 同步订单异常: platformOrderSn={}, error={}", platformOrderSn, e.getMessage());
                return false;
            }
        }

        private String generateSign(Map<String, Object> params) {
            List<String> keys = new ArrayList<>(params.keySet());
            Collections.sort(keys);
            StringBuilder sb = new StringBuilder(appSecret);
            for (String key : keys) {
                Object value = params.get(key);
                if (value != null && !value.toString().isEmpty()) {
                    sb.append(key).append(value.toString());
                }
            }
            sb.append(appSecret);
            return md5Sign(sb.toString());
        }
    }

    // ==================== 京东适配器 ====================
    @Slf4j
    public static class JdAdapter extends BaseAdapter {
        private final String apiUrl;
        private final String appKey;
        private final String appSecret;

        public JdAdapter(RestTemplate restTemplate, PlatformTokenService tokenService,
                        String apiUrl, String appKey, String appSecret) {
            super(restTemplate, tokenService);
            this.apiUrl = apiUrl != null && !apiUrl.isEmpty() ? apiUrl : "https://router.jd.com/api";
            this.appKey = appKey;
            this.appSecret = appSecret;
        }

        @Override
        public String getPlatformCode() { return "jd"; }
        @Override
        public String getPlatformName() { return "京东"; }

        @Override
        public boolean isConfigured() {
            return apiUrl != null && !apiUrl.isEmpty() && appKey != null && !appKey.isEmpty()
                    && appSecret != null && !appSecret.isEmpty();
        }

        @Override
        public List<PullOrdersResponse.PullOrderItem> pullOrders(Long shopId, String pullType,
                                                                  String orderIds, LocalDateTime startTime,
                                                                  LocalDateTime endTime) {
            if (!isConfigured()) {
                log.warn("[jd] 平台未配置，跳过拉取");
                return Collections.emptyList();
            }

            try {
                String token = tokenService.getToken("jd");
                if (token == null) token = "";

                Map<String, Object> params = new LinkedHashMap<>();
                params.put("method", "jd.order.search");
                params.put("app_key", appKey);
                params.put("timestamp", formatTime(LocalDateTime.now()));
                params.put("format", "json");
                params.put("v", "2.0");
                params.put("sign_method", "md5");
                params.put("access_token", token);
                params.put("page_size", 100);
                if (startTime != null) params.put("start_time", formatTime(startTime));
                if (endTime != null) params.put("end_time", formatTime(endTime));

                String sign = generateSign(params);
                params.put("sign", sign);

                String fullUrl = buildQueryUrl(apiUrl, params);
                log.info("[jd] 拉取订单: url={}, shopId={}, pullType={}, startTime={}",
                        apiUrl, shopId, pullType, startTime);

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

                PullOrdersResponse resp = httpCallAndParse(fullUrl, headers, null);
                if (resp != null && resp.getOrders() != null) {
                    log.info("[jd] 拉取成功: count={}", resp.getOrders().size());
                    return resp.getOrders();
                }

                return parseJdOrderResponse(fullUrl, headers);

            } catch (Exception e) {
                log.error("[jd] 拉取订单异常: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        private List<PullOrdersResponse.PullOrderItem> parseJdOrderResponse(String url, HttpHeaders headers) {
            try {
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(headers), String.class);
                String json = response.getBody();
                if (json == null || json.isEmpty()) return Collections.emptyList();

                Map<String, Object> root = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
                String orderKey = "jd_order_search_response";
                if (!root.containsKey(orderKey)) {
                    log.debug("[jd] 响应中无jd_order_search_response: {}", json);
                    return Collections.emptyList();
                }

                Map<String, Object> resp = (Map<String, Object>) root.get(orderKey);
                Object orderListObj = resp.get("order_list");
                if (orderListObj == null) return Collections.emptyList();

                List<Map<String, Object>> ordersRaw = (List<Map<String, Object>>) orderListObj;
                List<PullOrdersResponse.PullOrderItem> orders = new ArrayList<>();

                for (Map<String, Object> order : ordersRaw) {
                    PullOrdersResponse.PullOrderItem item = PullOrdersResponse.PullOrderItem.builder()
                            .orderSn(String.valueOf(order.get("order_id")))
                            .platformOrderSn(String.valueOf(order.get("order_id")))
                            .platform("jd")
                            .status(String.valueOf(order.get("status")))
                            .createdTime(String.valueOf(order.get("created_time")))
                            .payTime(String.valueOf(order.get("pay_time")))
                            .totalAmount(order.get("order_total") != null ?
                                    new java.math.BigDecimal(order.get("order_total").toString()) : java.math.BigDecimal.ZERO)
                            .build();
                    orders.add(item);
                }

                log.info("[jd] 解析订单成功: count={}", orders.size());
                return orders;
            } catch (Exception e) {
                log.error("[jd] 解析京东订单响应失败: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        @Override
        public boolean syncOrderToPlatform(String platformOrderSn, String syncStatus,
                                           String expressCompany, String expressNo) {
            if (!isConfigured()) {
                log.warn("[jd] 平台未配置，跳过同步");
                return false;
            }

            try {
                String token = tokenService.getToken("jd");
                if (token == null) token = "";

                Map<String, Object> params = new LinkedHashMap<>();
                params.put("method", "jd.logistics.online.send");
                params.put("app_key", appKey);
                params.put("timestamp", formatTime(LocalDateTime.now()));
                params.put("format", "json");
                params.put("v", "2.0");
                params.put("sign_method", "md5");
                params.put("access_token", token);
                params.put("order_id", platformOrderSn);
                if (expressCompany != null) params.put("logistics_company", expressCompany);
                if (expressNo != null) params.put("waybill", expressNo);

                String sign = generateSign(params);
                params.put("sign", sign);

                String fullUrl = buildQueryUrl(apiUrl, params);
                log.info("[jd] 同步订单发货: url={}, orderId={}, company={}, waybill={}",
                        apiUrl, platformOrderSn, expressCompany, expressNo);

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

                return httpSyncCall(fullUrl, headers, null);

            } catch (Exception e) {
                log.error("[jd] 同步订单异常: platformOrderSn={}, error={}", platformOrderSn, e.getMessage());
                return false;
            }
        }

        private String generateSign(Map<String, Object> params) {
            List<String> keys = new ArrayList<>(params.keySet());
            Collections.sort(keys);
            StringBuilder sb = new StringBuilder(appSecret);
            for (String key : keys) {
                Object value = params.get(key);
                if (value != null && !value.toString().isEmpty()) {
                    sb.append(key).append(value.toString());
                }
            }
            sb.append(appSecret);
            return md5Sign(sb.toString());
        }
    }

    // ==================== 拼多多适配器 ====================
    @Slf4j
    public static class PinduoduoAdapter extends BaseAdapter {
        private final String apiUrl;
        private final String clientId;
        private final String clientSecret;

        public PinduoduoAdapter(RestTemplate restTemplate, PlatformTokenService tokenService,
                               String apiUrl, String clientId, String clientSecret) {
            super(restTemplate, tokenService);
            this.apiUrl = apiUrl != null && !apiUrl.isEmpty() ? apiUrl : "https://gw-api.pinduoduo.com/api/router";
            this.clientId = clientId;
            this.clientSecret = clientSecret;
        }

        @Override
        public String getPlatformCode() { return "pinduoduo"; }
        @Override
        public String getPlatformName() { return "拼多多"; }

        @Override
        public boolean isConfigured() {
            return apiUrl != null && !apiUrl.isEmpty() && clientId != null && !clientId.isEmpty()
                    && clientSecret != null && !clientSecret.isEmpty();
        }

        @Override
        public List<PullOrdersResponse.PullOrderItem> pullOrders(Long shopId, String pullType,
                                                                  String orderIds, LocalDateTime startTime,
                                                                  LocalDateTime endTime) {
            if (!isConfigured()) {
                log.warn("[pinduoduo] 平台未配置，跳过拉取");
                return Collections.emptyList();
            }

            try {
                String token = tokenService.getToken("pinduoduo");
                if (token == null) token = "";

                Map<String, Object> params = new LinkedHashMap<>();
                params.put("type", "pdd.order.number.list.get");
                params.put("client_id", clientId);
                params.put("timestamp", currentTimestamp());
                params.put("sign_method", "md5");
                params.put("version", "v1");
                params.put("access_token", token);
                if (shopId != null) params.put("shop_id", shopId);
                if (startTime != null) params.put("start_time", formatTime(startTime));
                if (endTime != null) params.put("end_time", formatTime(endTime));

                String sign = generatePddSign(params);
                params.put("sign", sign);

                log.info("[pinduoduo] 拉取订单: url={}, shopId={}, pullType={}, startTime={}",
                        apiUrl, shopId, pullType, startTime);

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

                PullOrdersResponse resp = httpCallAndParse(apiUrl, headers, params);
                if (resp != null && resp.getOrders() != null) {
                    log.info("[pinduoduo] 拉取成功: count={}", resp.getOrders().size());
                    return resp.getOrders();
                }

                return parsePddOrderResponse(params, headers);

            } catch (Exception e) {
                log.error("[pinduoduo] 拉取订单异常: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        private List<PullOrdersResponse.PullOrderItem> parsePddOrderResponse(Map<String, Object> params, HttpHeaders headers) {
            try {
                // 拼多多使用POST表单方式
                HttpEntity<Map<String, Object>> entity = new HttpEntity<>(params, headers);
                ResponseEntity<String> response = restTemplate.exchange(apiUrl, HttpMethod.POST, entity, String.class);
                String json = response.getBody();
                if (json == null || json.isEmpty()) return Collections.emptyList();

                Map<String, Object> root = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
                String orderKey = "order_sn_list_response";
                if (!root.containsKey(orderKey)) {
                    log.debug("[pinduoduo] 响应中无order_sn_list_response: {}", json);
                    return Collections.emptyList();
                }

                Map<String, Object> resp = (Map<String, Object>) root.get(orderKey);
                Object orderListObj = resp.get("order_sn_list");
                if (orderListObj == null) return Collections.emptyList();

                List<String> orderSnList = (List<String>) orderListObj;
                List<PullOrdersResponse.PullOrderItem> orders = new ArrayList<>();

                for (String orderSn : orderSnList) {
                    PullOrdersResponse.PullOrderItem item = PullOrdersResponse.PullOrderItem.builder()
                            .orderSn(orderSn)
                            .platformOrderSn(orderSn)
                            .platform("pinduoduo")
                            .build();
                    orders.add(item);
                }

                log.info("[pinduoduo] 解析订单成功: count={}", orders.size());
                return orders;
            } catch (Exception e) {
                log.error("[pinduoduo] 解析拼多多订单响应失败: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        @Override
        public boolean syncOrderToPlatform(String platformOrderSn, String syncStatus,
                                           String expressCompany, String expressNo) {
            if (!isConfigured()) {
                log.warn("[pinduoduo] 平台未配置，跳过同步");
                return false;
            }

            try {
                String token = tokenService.getToken("pinduoduo");
                if (token == null) token = "";

                Map<String, Object> params = new LinkedHashMap<>();
                params.put("type", "pdd.logistics.online.send");
                params.put("client_id", clientId);
                params.put("timestamp", currentTimestamp());
                params.put("sign_method", "md5");
                params.put("version", "v1");
                params.put("access_token", token);
                params.put("order_sn", platformOrderSn);
                if (expressCompany != null) params.put("logistics_code", expressCompany);
                if (expressNo != null) params.put("waybill_no", expressNo);

                String sign = generatePddSign(params);
                params.put("sign", sign);

                log.info("[pinduoduo] 同步订单发货: url={}, orderSn={}, company={}, waybill={}",
                        apiUrl, platformOrderSn, expressCompany, expressNo);

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

                return httpSyncCall(apiUrl, headers, params);

            } catch (Exception e) {
                log.error("[pinduoduo] 同步订单异常: platformOrderSn={}, error={}", platformOrderSn, e.getMessage());
                return false;
            }
        }

        private String generatePddSign(Map<String, Object> params) {
            List<String> keys = new ArrayList<>(params.keySet());
            Collections.sort(keys);
            StringBuilder sb = new StringBuilder(clientSecret);
            for (String key : keys) {
                Object value = params.get(key);
                if (value != null && !value.toString().isEmpty()) {
                    sb.append(key).append(value.toString());
                }
            }
            sb.append(clientSecret);
            return md5Sign(sb.toString()).toUpperCase();
        }
    }

    // ==================== 抖音小店适配器 ====================
    @Slf4j
    public static class DouyinAdapter extends BaseAdapter {
        private final String apiUrl;
        private final String clientKey;
        private final String clientSecret;

        public DouyinAdapter(RestTemplate restTemplate, PlatformTokenService tokenService,
                            String apiUrl, String clientKey, String clientSecret) {
            super(restTemplate, tokenService);
            this.apiUrl = apiUrl != null && !apiUrl.isEmpty() ? apiUrl : "https://open.douyin.com";
            this.clientKey = clientKey;
            this.clientSecret = clientSecret;
        }

        @Override
        public String getPlatformCode() { return "douyin"; }
        @Override
        public String getPlatformName() { return "抖音小店"; }

        @Override
        public boolean isConfigured() {
            return apiUrl != null && !apiUrl.isEmpty() && clientKey != null && !clientKey.isEmpty()
                    && clientSecret != null && !clientSecret.isEmpty();
        }

        @Override
        public List<PullOrdersResponse.PullOrderItem> pullOrders(Long shopId, String pullType,
                                                                  String orderIds, LocalDateTime startTime,
                                                                  LocalDateTime endTime) {
            if (!isConfigured()) {
                log.warn("[douyin] 平台未配置，跳过拉取");
                return Collections.emptyList();
            }

            try {
                String token = tokenService.getToken("douyin");
                if (token == null || token.isEmpty()) {
                    log.warn("[douyin] access_token为空，请先授权获取token");
                    return Collections.emptyList();
                }

                StringBuilder urlBuilder = new StringBuilder(apiUrl)
                        .append("/order/list/?access_token=").append(token)
                        .append("&start_time=").append(startTime != null ? toUnixTimestamp(startTime) : toUnixTimestamp(LocalDateTime.now().minusHours(24)))
                        .append("&end_time=").append(endTime != null ? toUnixTimestamp(endTime) : toUnixTimestamp(LocalDateTime.now()));

                if (shopId != null) {
                    urlBuilder.append("&shop_id=").append(shopId);
                }

                String url = urlBuilder.toString();
                log.info("[douyin] 拉取订单: url={}, shopId={}, pullType={}", apiUrl, shopId, pullType);

                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                headers.set("Authorization", "Bearer " + token);

                PullOrdersResponse resp = httpCallAndParse(url, headers, null);
                if (resp != null && resp.getOrders() != null) {
                    log.info("[douyin] 拉取成功: count={}", resp.getOrders().size());
                    return resp.getOrders();
                }

                return parseDouyinOrderResponse(url, headers);

            } catch (Exception e) {
                log.error("[douyin] 拉取订单异常: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        private List<PullOrdersResponse.PullOrderItem> parseDouyinOrderResponse(String url, HttpHeaders headers) {
            try {
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(headers), String.class);
                String json = response.getBody();
                if (json == null || json.isEmpty()) return Collections.emptyList();

                Map<String, Object> root = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
                
                // 抖音返回格式: { "data": { "order_list": [...] }, "errno": 0, "errmsg": "" }
                Object dataObj = root.get("data");
                if (dataObj == null) {
                    log.debug("[douyin] 响应中无data: {}", json);
                    return Collections.emptyList();
                }

                Map<String, Object> data = (Map<String, Object>) dataObj;
                Object orderListObj = data.get("order_list");
                if (orderListObj == null) return Collections.emptyList();

                List<Map<String, Object>> ordersRaw = (List<Map<String, Object>>) orderListObj;
                List<PullOrdersResponse.PullOrderItem> orders = new ArrayList<>();

                for (Map<String, Object> order : ordersRaw) {
                    PullOrdersResponse.PullOrderItem item = PullOrdersResponse.PullOrderItem.builder()
                            .orderSn(String.valueOf(order.get("order_id")))
                            .platformOrderSn(String.valueOf(order.get("order_id")))
                            .platform("douyin")
                            .status(String.valueOf(order.get("status")))
                            .createdTime(String.valueOf(order.get("create_time")))
                            .payTime(String.valueOf(order.get("pay_time")))
                            .totalAmount(order.get("total_amount") != null ?
                                    new java.math.BigDecimal(order.get("total_amount").toString()) : java.math.BigDecimal.ZERO)
                            .build();
                    orders.add(item);
                }

                log.info("[douyin] 解析订单成功: count={}", orders.size());
                return orders;
            } catch (Exception e) {
                log.error("[douyin] 解析抖音订单响应失败: {}", e.getMessage());
                return Collections.emptyList();
            }
        }

        @Override
        public boolean syncOrderToPlatform(String platformOrderSn, String syncStatus,
                                           String expressCompany, String expressNo) {
            if (!isConfigured()) {
                log.warn("[douyin] 平台未配置，跳过同步");
                return false;
            }

            try {
                String token = tokenService.getToken("douyin");
                if (token == null || token.isEmpty()) {
                    log.warn("[douyin] access_token为空，请先授权获取token");
                    return false;
                }

                String url = apiUrl + "/order/deliver/?access_token=" + token;
                log.info("[douyin] 同步订单发货: url={}, orderId={}, company={}, expressNo={}",
                        apiUrl, platformOrderSn, expressCompany, expressNo);

                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                headers.set("Authorization", "Bearer " + token);

                Map<String, Object> body = new LinkedHashMap<>();
                body.put("order_id", platformOrderSn);
                if (expressCompany != null) body.put("express_company", expressCompany);
                if (expressNo != null) body.put("waybill_no", expressNo);

                return httpSyncCall(url, headers, body);

            } catch (Exception e) {
                log.error("[douyin] 同步订单异常: platformOrderSn={}, error={}", platformOrderSn, e.getMessage());
                return false;
            }
        }

        private long toUnixTimestamp(LocalDateTime time) {
            return time.toEpochSecond(ZoneOffset.of("+8"));
        }
    }

    // ==================== 工厂主体 ====================
    private final Map<String, PlatformAdapter> adapters = new ConcurrentHashMap<>();
    private final PlatformTokenService tokenService;

    @Value("${erp.platform.taobao.api-url:}")
    private String taobaoApiUrl;

    @Value("${erp.platform.taobao.app-key:}")
    private String taobaoAppKey;

    @Value("${erp.platform.taobao.app-secret:}")
    private String taobaoAppSecret;

    @Value("${erp.platform.jd.api-url:}")
    private String jdApiUrl;

    @Value("${erp.platform.jd.app-key:}")
    private String jdAppKey;

    @Value("${erp.platform.jd.app-secret:}")
    private String jdAppSecret;

    @Value("${erp.platform.pinduoduo.api-url:}")
    private String pddApiUrl;

    @Value("${erp.platform.pinduoduo.client-id:}")
    private String pddClientId;

    @Value("${erp.platform.pinduoduo.client-secret:}")
    private String pddClientSecret;

    @Value("${erp.platform.douyin.api-url:}")
    private String douyinApiUrl;

    @Value("${erp.platform.douyin.client-key:}")
    private String douyinClientKey;

    @Value("${erp.platform.douyin.client-secret:}")
    private String douyinClientSecret;

    public PlatformAdapterFactory(StringRedisTemplate redisTemplate) {
        this.tokenService = new PlatformTokenService(redisTemplate);
    }

    @PostConstruct
    public void init() {
        RestTemplate restTemplate = createRestTemplate();

        // 注册各平台适配器
        registerAdapter(new TaobaoAdapter(restTemplate, tokenService, taobaoApiUrl, taobaoAppKey, taobaoAppSecret));
        registerAdapter(new JdAdapter(restTemplate, tokenService, jdApiUrl, jdAppKey, jdAppSecret));
        registerAdapter(new PinduoduoAdapter(restTemplate, tokenService, pddApiUrl, pddClientId, pddClientSecret));
        registerAdapter(new DouyinAdapter(restTemplate, tokenService, douyinApiUrl, douyinClientKey, douyinClientSecret));

        log.info("平台适配器初始化完成: {}", adapters.keySet());
    }

    private RestTemplate createRestTemplate() {
        org.springframework.http.client.SimpleClientHttpRequestFactory factory =
                new org.springframework.http.client.SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(10000);
        factory.setReadTimeout(30000);
        return new RestTemplate(factory);
    }

    private void registerAdapter(PlatformAdapter adapter) {
        if (adapter.getPlatformCode() != null && !adapter.getPlatformCode().isEmpty()) {
            adapters.put(adapter.getPlatformCode(), adapter);
            log.info("注册平台适配器: {} - {}", adapter.getPlatformCode(), adapter.getPlatformName());
        }
    }

    public PlatformAdapter getAdapter(String platformCode) {
        return adapters.get(platformCode);
    }

    public Set<String> getSupportedPlatforms() {
        return new HashSet<>(adapters.keySet());
    }

    /**
     * 获取Token缓存服务（供外部使用）
     */
    public PlatformTokenService getTokenService() {
        return tokenService;
    }
}
