package com.nanri.aiimage.modules.ziniao.client;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nanri.aiimage.common.exception.BusinessException;
import com.nanri.aiimage.config.ZiniaoProperties;
import com.nanri.aiimage.modules.ziniao.model.cache.ZiniaoShopCacheDto;
import com.nanri.aiimage.modules.ziniao.model.vo.ZiniaoStaffItemVo;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;

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

@Component
@RequiredArgsConstructor
public class ZiniaoClientImpl implements ZiniaoClient {

    private final ZiniaoProperties ziniaoProperties;
    private final ObjectMapper objectMapper;

    @Override
    public Long getCompanyIdByApiKey(String apiKey) {
        String raw = getWithApiKey(apiKey, "/app/builtin/company", "获取 companyId");
        try {
            JsonNode root = objectMapper.readTree(raw);
            JsonNode data = firstNonNull(root.get("data"), root.get("result"), root);
            Long companyId = longValue(firstNonNull(data == null ? null : data.get("companyId"), root.get("companyId")));
            if (companyId == null || companyId <= 0) {
                throw new BusinessException("紫鸟 companyId 响应缺少 companyId");
            }
            return companyId;
        } catch (BusinessException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new BusinessException("解析紫鸟 companyId 响应失败");
        }
    }

    @Override
    public List<ZiniaoStaffItemVo> listStaff(String apiKey, Long companyId) {
        String raw = postWithApiKey(apiKey, ziniaoProperties.getStaffListPath(), Map.of(
                "companyId", String.valueOf(companyId),
                "level", "",
                "isAccurate", "",
                "limit", "100",
                "page", "1",
                "departmentIds", List.of(),
                "delflag", "",
                "name", "",
                "username", ""
        ), "获取员工列表");
        try {
            JsonNode root = objectMapper.readTree(raw);
            JsonNode dataNode = firstNonNull(root.get("data"), root.get("result"));
            JsonNode itemsNode = dataNode == null ? null : firstNonNull(dataNode.get("data"), dataNode.get("items"), dataNode);
            List<ZiniaoStaffItemVo> items = new ArrayList<>();
            if (itemsNode != null && itemsNode.isArray()) {
                for (JsonNode itemNode : itemsNode) {
                    addStaffItem(items, itemNode);
                }
            } else if (itemsNode != null && itemsNode.isObject()) {
                addStaffItem(items, itemsNode);
            }
            return items;
        } catch (Exception ex) {
            throw new BusinessException("解析紫鸟员工列表失败");
        }
    }

    @Override
    public List<ZiniaoShopCacheDto> listUserStores(String apiKey, Long companyId, Long userId) {
        String raw = postWithApiKey(apiKey, ziniaoProperties.getUserStoresPath(), Map.of(
                "companyId", String.valueOf(companyId),
                "isAccurate", "",
                "limit", "100",
                "storeName", "",
                "page", "1",
                "userId", String.valueOf(userId)
        ), "获取员工店铺列表");
        return parseUserStores(raw);
    }

    @Override
    public String getUserLoginToken(String apiKey, Long companyId, Long userId) {
        String raw = postWithApiKey(apiKey, ziniaoProperties.getUserLoginTokenPath(), Map.of(
                "companyId", String.valueOf(companyId),
                "userId", String.valueOf(userId)
        ), "获取员工登录 token");
        try {
            JsonNode root = objectMapper.readTree(raw);
            if (!success(root)) {
                throw new BusinessException("获取紫鸟员工登录 token 失败: " + Objects.toString(text(root.get("msg")), "未知错误"));
            }
            JsonNode data = firstNonNull(root.get("data"), root.get("result"));
            JsonNode payload = firstNonNull(
                    data == null ? null : data.get("data"),
                    data == null ? null : data.get("result"),
                    data,
                    root
            );
            String token = text(firstNonNull(
                    payload == null ? null : payload.get("token"),
                    payload == null ? null : payload.get("loginToken"),
                    data == null ? null : data.get("token"),
                    data == null ? null : data.get("loginToken"),
                    root.get("token"),
                    root.get("loginToken")
            ));
            if (token == null || token.isBlank()) {
                throw new BusinessException("紫鸟员工登录 token 响应缺少 token");
            }
            return token;
        } catch (BusinessException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new BusinessException("解析紫鸟员工登录 token 响应失败");
        }
    }


    private String getWithApiKey(String apiKey, String path, String action) {
        String raw = getRestClient().get()
                .uri(joinUrl(ziniaoProperties.getBaseUrl(), path))
                .headers(headers -> applyAuthorization(headers, apiKey))
                .retrieve()
                .onStatus(HttpStatusCode::isError, (req, res) -> {
                    // 保留响应体，交给后续 validateSuccess 统一解析
                })
                .body(String.class);
        validateSuccess(raw, action, path);
        return raw;
    }

    private String postWithApiKey(String apiKey, String path, Map<String, Object> body, String action) {
        RestClient.RequestBodySpec request = getRestClient().post()
                .uri(joinUrl(ziniaoProperties.getBaseUrl(), path))
                .headers(headers -> {
                    applyAuthorization(headers, apiKey);
                    headers.setContentType(MediaType.APPLICATION_JSON);
                });
        if (body != null) {
            request.body(body);
        }
        String raw = request
                .retrieve()
                .onStatus(HttpStatusCode::isError, (req, res) -> {
                    // 保留响应体，交给后续 validateSuccess 统一解析 code/sub_code/sub_msg
                })
                .body(String.class);
        validateSuccess(raw, action, path);
        return raw;
    }

    private String postWithAuthorization(String path, String authorization, Map<String, Object> body, String action) {
        String token = requireText(authorization, "紫鸟授权 token 未配置");
        RestClient.RequestBodySpec request = getRestClient().post()
                .uri(joinUrl(ziniaoProperties.getBaseUrl(), path))
                .headers(headers -> {
                    if (token.regionMatches(true, 0, "Bearer ", 0, 7)) {
                        headers.set("Authorization", token);
                    } else {
                        headers.setBearerAuth(token);
                    }
                    headers.setContentType(MediaType.APPLICATION_JSON);
                });
        if (body != null) {
            request.body(body);
        }
        String raw = request
                .retrieve()
                .body(String.class);
        validateSuccess(raw, action, path);
        return raw;
    }

    private void applyAuthorization(org.springframework.http.HttpHeaders headers, String apiKey) {
        String token = requireText(apiKey, "紫鸟 apiKey 未配置");
        if (token.regionMatches(true, 0, "Bearer ", 0, 7)) {
            headers.set("Authorization", token);
        } else {
            headers.setBearerAuth(token);
        }
    }

    private void validateSuccess(String raw, String action, String path) {
        try {
            JsonNode root = objectMapper.readTree(raw);
            if (!success(root)) {
                String code = Objects.toString(text(root.get("code")), "");
                String msg = Objects.toString(text(root.get("msg")), "未知错误");
                String subCode = Objects.toString(text(root.get("sub_code")), "");
                String subMsg = Objects.toString(text(root.get("sub_msg")), "");

                StringBuilder detail = new StringBuilder();
                if (!code.isBlank()) {
                    detail.append("code=").append(code);
                }
                if (!subCode.isBlank()) {
                    if (!detail.isEmpty()) detail.append(", ");
                    detail.append("sub_code=").append(subCode);
                }
                if (!subMsg.isBlank()) {
                    if (!detail.isEmpty()) detail.append(", ");
                    detail.append("sub_msg=").append(subMsg);
                }
                if (!detail.isEmpty()) {
                    detail.append(", ");
                }
                detail.append("msg=").append(msg);

                throw new BusinessException("紫鸟接口返回失败(" + action + ", " + path + "): " + detail);
            }
        } catch (BusinessException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new BusinessException("解析紫鸟接口响应失败(" + action + ", " + path + ")");
        }
    }

    private boolean success(JsonNode root) {
        String code = text(root.get("code"));
        if (code != null && !"0".equals(code)) {
            return false;
        }
        String status = text(root.get("status"));
        Long ret = longValue(root.get("ret"));
        if ((ret != null && ret != 0L) || (status != null && !"success".equalsIgnoreCase(status))) {
            return false;
        }
        JsonNode wrapper = root.get("data");
        if (wrapper != null && wrapper.isObject()) {
            String wrapperStatus = text(wrapper.get("status"));
            Long wrapperRet = longValue(wrapper.get("ret"));
            if ((wrapperRet != null && wrapperRet != 0L) || (wrapperStatus != null && !"success".equalsIgnoreCase(wrapperStatus))) {
                return false;
            }
        }
        return true;
    }

    private RestClient getRestClient() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(ziniaoProperties.getConnectTimeoutSeconds() * 1000);
        requestFactory.setReadTimeout(ziniaoProperties.getReadTimeoutSeconds() * 1000);
        return RestClient.builder().requestFactory(requestFactory).build();
    }

    private void addStaffItem(List<ZiniaoStaffItemVo> items, JsonNode itemNode) {
        ZiniaoStaffItemVo item = new ZiniaoStaffItemVo();
        item.setUserId(longValue(firstNonNull(itemNode.get("userId"), itemNode.get("user_id"))));
        item.setUsername(text(firstNonNull(itemNode.get("username"), itemNode.get("userName"))));
        item.setName(text(itemNode.get("name")));
        if (item.getUserId() != null) {
            items.add(item);
        }
    }

    private List<ZiniaoShopCacheDto> parseShops(String raw) {
        try {
            JsonNode root = objectMapper.readTree(raw);
            JsonNode wrapper = root.get("data");
            JsonNode itemsNode = wrapper == null ? null : wrapper.get("data");
            List<ZiniaoShopCacheDto> items = new ArrayList<>();
            if (itemsNode != null && itemsNode.isArray()) {
                for (JsonNode itemNode : itemsNode) {
                    ZiniaoShopCacheDto item = new ZiniaoShopCacheDto();
                    item.setShopId(text(firstNonNull(itemNode.get("shopId"), itemNode.get("id"), itemNode.get("accountId"), itemNode.get("account_id"))));
                    item.setShopName(text(firstNonNull(itemNode.get("shopName"), itemNode.get("name"), itemNode.get("accountName"), itemNode.get("account_name"))));
                    item.setPlatform(text(firstNonNull(itemNode.get("platform"), itemNode.get("platformName"), itemNode.get("site"), itemNode.get("siteName"))));
                    if (item.getShopId() != null && !item.getShopId().isBlank()) {
                        items.add(item);
                    }
                }
            }
            return items;
        } catch (Exception ex) {
            throw new BusinessException("解析紫鸟店铺列表失败");
        }
    }
    private List<ZiniaoShopCacheDto> parseUserStores(String raw) {
        try {
            JsonNode root = objectMapper.readTree(raw);
            JsonNode wrapper = firstNonNull(root.get("data"), root.get("result"), root);
            JsonNode itemsNode = firstNonNull(
                    wrapper == null ? null : wrapper.get("data"),
                    wrapper == null ? null : wrapper.get("items"),
                    wrapper
            );

            List<ZiniaoShopCacheDto> items = new ArrayList<>();
            if (itemsNode != null && itemsNode.isArray()) {
                for (JsonNode itemNode : itemsNode) {
                    ZiniaoShopCacheDto item = new ZiniaoShopCacheDto();
                    item.setShopId(text(firstNonNull(itemNode.get("id"), itemNode.get("shopId"), itemNode.get("accountId"), itemNode.get("account_id"))));
                    item.setShopName(text(firstNonNull(itemNode.get("name"), itemNode.get("shopName"), itemNode.get("accountName"), itemNode.get("account_name"))));
                    item.setPlatform(text(firstNonNull(itemNode.get("platform"), itemNode.get("platformName"), itemNode.get("site"), itemNode.get("siteName"))));
                    if (item.getShopId() != null && !item.getShopId().isBlank()) {
                        items.add(item);
                    }
                }
            }
            return items;
        } catch (Exception ex) {
            throw new BusinessException("解析紫鸟员工店铺列表失败");
        }
    }



    private String joinUrl(String baseUrl, String path) {
        String base = Objects.toString(baseUrl, "").trim();
        String suffix = Objects.toString(path, "").trim();
        if (base.endsWith("/") && suffix.startsWith("/")) {
            return base + suffix.substring(1);
        }
        if (!base.endsWith("/") && !suffix.startsWith("/")) {
            return base + "/" + suffix;
        }
        return base + suffix;
    }

    private JsonNode firstNonNull(JsonNode... nodes) {
        for (JsonNode node : nodes) {
            if (node != null && !node.isNull()) {
                return node;
            }
        }
        return null;
    }

    private String text(JsonNode node) {
        if (node == null || node.isNull()) {
            return null;
        }
        String value = node.asText();
        return value == null || value.isBlank() ? null : value.trim();
    }

    private Long longValue(JsonNode node) {
        if (node == null || node.isNull()) {
            return null;
        }
        try {
            return node.asLong();
        } catch (Exception ex) {
            return null;
        }
    }

    private String requireText(String value, String message) {
        if (value == null || value.isBlank() || "change-me".equalsIgnoreCase(value.trim())) {
            throw new BusinessException(message);
        }
        return value.trim();
    }
}
