package com.kym.service.awoara;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.google.gson.*;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.entity.DeviceConfig;
import com.kym.entity.awoara.ApiList;
import com.kym.entity.awoara.MethodHelp;
import com.kym.entity.awoara.OrderInfo;
import com.kym.entity.awoara.OrderInfoObject;
import com.kym.entity.awoara.response.AwoaraResponse;
import com.kym.entity.awoara.response.CreateOrder;
import com.kym.entity.awoara.response.HardwareInfo;
import com.kym.entity.awoara.response.State;
import com.kym.service.aliyun.lot.AliyunLotClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Base64;

import static cn.hutool.http.HttpStatus.HTTP_OK;

/**
 * 石斑鱼主板API
 *
 * @author skyline
 */
@Service
@Slf4j
public class AwoaraServiceImpl implements AwoaraService {


    static final Gson gson = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter())
            .registerTypeAdapter(Boolean.class, (JsonDeserializer<Boolean>) (json, typeOfT, context) -> {
                if (json.isJsonPrimitive()) {
                    JsonPrimitive primitive = json.getAsJsonPrimitive();
                    if (primitive.isNumber()) return primitive.getAsInt() != 0;
                    if (primitive.isBoolean()) return primitive.getAsBoolean();
                    if (primitive.isString()) {
                        String s = primitive.getAsString();
                        return "1".equals(s) || "true".equalsIgnoreCase(s);
                    }
                }
                return false;
            })
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create();

    /**
     * BASE64解码器
     */
    private static final Base64.Decoder DECODER = Base64.getDecoder();

    static <T> T doRequest(String productKey, String deviceName, String params, TypeReference<AwoaraResponse<T>>... typeReference) {
        try {
            var response = AliyunLotClient.rRpc(productKey, deviceName, params);
            if (HTTP_OK != response.getStatusCode()) {
                log.error("AliyunLot响应码:{}", response.getStatusCode());
                throw new BusinessException("AliyunLot响应异常");
            }

            // 检查 RRpc 层是否成功（设备离线等情况会返回 Success=false）
            var body = response.getBody();
            if (body.success == null || !body.success) {
                String rrpcCode = body.rrpcCode != null ? body.rrpcCode : "UNKNOWN";
                String errorMsg = body.errorMessage != null ? body.errorMessage : "未知错误";
                log.error("AliyunLot RRpc失败，RrpcCode:{}，ErrorMessage:{}", rrpcCode, errorMsg);
                throw new BusinessException("设备" + ("OFFLINE".equals(rrpcCode) ? "离线" : "响应异常：" + errorMsg));
            }

            if (body.payloadBase64Byte == null) {
                log.error("AliyunLot响应payload为空");
                throw new BusinessException("AliyunLot响应数据为空");
            }

            AwoaraResponse<T> res;
            if (CommUtil.isNotEmptyAndNull(typeReference)) {
                res = JSONObject.parseObject(new String(DECODER.decode(body.payloadBase64Byte), StandardCharsets.UTF_8), typeReference[0]);
                log.debug("AliyunLot返回结果：{}", res);
            } else {
                res = JSONObject.parseObject(new String(DECODER.decode(body.payloadBase64Byte), StandardCharsets.UTF_8), AwoaraResponse.class);
            }
            if (HTTP_OK == res.getCode()) {
                return res.getData();
            } else {
                log.error("AliyunLot响应异常:{}", res);
                throw new BusinessException("AliyunLot响应异常");
            }
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("AliyunLot请求异常:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public ApiList help(String productKey, String deviceName) {
        var params = """
                {
                    "version": "2.0",
                    "method": "help",
                    "params": []
                }
                """;
        return doRequest(productKey, deviceName, params, new TypeReference<AwoaraResponse<ApiList>>() {
        });
    }

    @Override
    public MethodHelp methodHelp(String productKey, String deviceName, String method) {
        var params = """
                {
                    "version": "2.0",
                    "method": "help",
                    "params": {
                        "method": "%s"
                     }
                }
                """.formatted(method);
        return doRequest(productKey, deviceName, params, new TypeReference<AwoaraResponse<MethodHelp>>() {
        });

    }

    @Override
    public void showMsgbox(String productKey, String deviceName, String title, String content, int seconds) {
        var params = """
                {
                    "version": "2.0",
                        "method": "show_msgbox",
                        "params": {
                            "title": "%s",
                            "content": "%s",
                            "seconds": %d
                        }
                }
                """.formatted(title, content, seconds);

        doRequest(productKey, deviceName, params, null);
    }

    @Override
    public void hideMsgbox(String productKey, String deviceName) {
        var params = """
                {
                    "version": "2.0",
                    "method": "hide_msgbox",
                    "params": []
                }
                """;
        doRequest(productKey, deviceName, params, null);
    }

    @Override
    public void reboot(String productKey, String deviceName) {
        var params = """
                {
                    "version": "2.0",
                    "method": "reboot",
                    "params": []
                }
                """;
        doRequest(productKey, deviceName, params, null);
    }

    @Override
    public State queryState(String productKey, String deviceName) {
        var params = """
                {
                    "version": "2.0",
                    "method": "query_state",
                    "params": []
                }
                """;
        return doRequest(productKey, deviceName, params, new TypeReference<AwoaraResponse<State>>() {
        });
    }

    @Override
    public HardwareInfo queryHardwareInfo(String productKey, String deviceName) {
        var params = """
                {
                    "version": "2.0",
                    "method": "query_hardware_info",
                    "params": []
                }
                """;
        return doRequest(productKey, deviceName, params, new TypeReference<AwoaraResponse<HardwareInfo>>() {
        });
    }

    @Override
    public CreateOrder createOrder(String productKey, String deviceName, String orderId, String memberName, int memberBalance, int memberDiscount, int prepayMoney) {
        var params = """
                {
                    "version": "2.0",
                    "method": "create_order",
                    "params": {
                        "order_id": "%s",
                        "member_name": "%s",
                        "member_balance": %d,
                        "member_discount": %d,
                        "prepay_money": %d
                    }
                }
                """.formatted(orderId, memberName, memberBalance, memberDiscount, prepayMoney);
        return doRequest(productKey, deviceName, params, new TypeReference<AwoaraResponse<CreateOrder>>() {
        });
    }

    @Override
    public void closeOrder(String productKey, String deviceName, String orderId) {
        var params = """
                {
                    "version": "2.0",
                    "method": "close_order",
                    "params": {
                        "order_id": "%s"
                     }
                }
                """.formatted(orderId);
        doRequest(productKey, deviceName, params, null);
    }

    @Override
    public void forceCloseOrder(String productKey, String deviceName) {
        var params = """
                {
                    "version": "2.0",
                    "method": "close_order",
                    "params": {
                        "force_close": 1
                     }
                }
                """;
        doRequest(productKey, deviceName, params, null);
    }

    @Override
    public OrderInfo queryOrder(String productKey, String deviceName, String orderId) {
        var params = """
                {
                    "version": "2.0",
                    "method": "query_order",
                    "params": {
                        "order_id": "%s"
                     }
                }
                """.formatted(orderId);
        OrderInfoObject res = doRequest(productKey, deviceName, params,
                new TypeReference<AwoaraResponse<OrderInfoObject>>() {});
        return res != null ? res.getOrder_info() : null;
    }

    @Override
    public DeviceConfig readConfig(String productKey, String deviceName) {
        var params = """
                {
                    "version": "2.0",
                    "method": "read_config",
                    "params": []
                }
                """;
        var res = doRequest(productKey, deviceName, params, null);
        log.debug("readConfig: {}", res);
        return gson.fromJson(JSON.toJSONString(res).replaceAll("\\.", ""), DeviceConfig.class);
    }

    @Override
    public void writeConfig(String productKey, String deviceName, DeviceConfig deviceConfig) {
        var json = new JSONObject();
        json.put("version", "2.0");
        json.put("method", "write_config");
        json.put("params", deviceConfig);
        doRequest(productKey, deviceName, gson.toJson(json).replaceAll("1\"", ".1\"").replaceAll("2\"", ".2\""), null);
    }
}
