package com.red.circle.order.app.common.task;

import com.alibaba.fastjson.JSON;
import com.red.circle.component.mq.MessageEvent;
import com.red.circle.mq.rocket.business.service.MessageSenderService;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class TaskCenterGoClient {

  private static final String EVENT_TYPE_RECHARGE_GOLD = "RECHARGE_GOLD";

  private final ObjectProvider<MessageSenderService> messageSenderServiceProvider;

  @Value("${task.center.go.enabled:true}")
  private boolean enabled;

  @Value("${task.center.go.base-url:}")
  private String baseUrl;

  @Value("${task.center.go.internal-token:}")
  private String internalToken;

  @Value("${task.center.go.timeout-millis:3000}")
  private Integer timeoutMillis;

  @Value("${task.center.event.mq.enabled:false}")
  private boolean mqEnabled;

  @Value("${task.center.event.mq.topic:RC_DEFAULT_APP_ORDINARY}")
  private String mqTopic;

  @Value("${task.center.event.mq.tag:task_center_event}")
  private String mqTag;

  public TaskCenterGoClient(ObjectProvider<MessageSenderService> messageSenderServiceProvider) {
    this.messageSenderServiceProvider = messageSenderServiceProvider;
  }

  public void reportRechargeGold(String sysOrigin,
      Long userId,
      Long purchaseHistoryId,
      BigDecimal candyQuantity,
      String platform,
      String payPlatform,
      Instant occurredAt) {
    if (Objects.isNull(userId) || Objects.isNull(purchaseHistoryId) || Objects.isNull(candyQuantity)) {
      return;
    }
    long deltaValue = candyQuantity.setScale(0, RoundingMode.DOWN).longValue();
    if (deltaValue <= 0) {
      return;
    }

    Map<String, Object> payload = new HashMap<>();
    payload.put("purchaseHistoryId", purchaseHistoryId);
    payload.put("candyQuantity", candyQuantity);
    payload.put("platform", platform);
    payload.put("payPlatform", payPlatform);

    reportEvent(new TaskCenterEventRequest()
        .setSysOrigin(sysOrigin)
        .setEventId("RECHARGE_GOLD:" + purchaseHistoryId)
        .setEventType(EVENT_TYPE_RECHARGE_GOLD)
        .setUserId(userId)
        .setDeltaValue(deltaValue)
        .setOccurredAt(Objects.requireNonNullElse(occurredAt, Instant.now()).toString())
        .setPayload(payload));
  }

  private void reportEvent(TaskCenterEventRequest request) {
    if (mqEnabled) {
      publishMqEvent(request);
    }
    if (!enabled) {
      return;
    }
    String normalizedBaseUrl = trimRightSlash(Objects.toString(baseUrl, "").trim());
    if (normalizedBaseUrl.isEmpty()) {
      log.warn("Task center go baseUrl is blank, skip event report. eventId={}", request.getEventId());
      return;
    }

    HttpURLConnection connection = null;
    try {
      URL url = new URL(normalizedBaseUrl + "/internal/task-center/event");
      connection = (HttpURLConnection) url.openConnection();
      int timeout = Objects.requireNonNullElse(timeoutMillis, 3000);
      connection.setConnectTimeout(timeout);
      connection.setReadTimeout(timeout);
      connection.setRequestMethod("POST");
      connection.setDoOutput(true);
      connection.setRequestProperty("Content-Type", "application/json");
      connection.setRequestProperty("Accept", "application/json");
      connection.setRequestProperty("X-Internal-Token", Objects.toString(internalToken, ""));

      byte[] body = JSON.toJSONString(request).getBytes(StandardCharsets.UTF_8);
      try (OutputStream outputStream = connection.getOutputStream()) {
        outputStream.write(body);
      }

      int status = connection.getResponseCode();
      if (status < 200 || status >= 300) {
        log.warn("Task center go report failed. status={}, body={}, eventId={}",
            status, readResponse(connection), request.getEventId());
      }
    } catch (Exception e) {
      log.warn("Task center go report error. eventId={}", request.getEventId(), e);
    } finally {
      if (Objects.nonNull(connection)) {
        connection.disconnect();
      }
    }
  }

  private void publishMqEvent(TaskCenterEventRequest request) {
    try {
      MessageSenderService senderService = messageSenderServiceProvider.getIfAvailable();
      if (Objects.isNull(senderService)) {
        log.warn("Task center mq sender missing, skip event report. eventId={}", request.getEventId());
        return;
      }
      senderService.sendEventMessage(MessageEvent.builder()
          .consumeId(request.getEventId())
          .topicString(defaultIfBlank(mqTopic, "RC_DEFAULT_APP_ORDINARY"))
          .tag(defaultIfBlank(mqTag, "task_center_event"))
          .body(request)
          .build());
    } catch (Exception e) {
      log.warn("Task center mq report error. eventId={}", request.getEventId(), e);
    }
  }

  private String readResponse(HttpURLConnection connection) {
    try (InputStream inputStream = connection.getErrorStream() != null
        ? connection.getErrorStream()
        : connection.getInputStream()) {
      if (Objects.isNull(inputStream)) {
        return "";
      }
      return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
    } catch (Exception e) {
      return "";
    }
  }

  private String trimRightSlash(String value) {
    while (value.endsWith("/")) {
      value = value.substring(0, value.length() - 1);
    }
    return value;
  }

  private String defaultIfBlank(String value, String fallback) {
    String normalized = Objects.toString(value, "").trim();
    return normalized.isEmpty() ? fallback : normalized;
  }

  @Data
  @Accessors(chain = true)
  private static class TaskCenterEventRequest {
    private String sysOrigin;
    private String eventId;
    private String eventType;
    private Long userId;
    private Long deltaValue;
    private String occurredAt;
    private Map<String, Object> payload;
  }
}
