package chirp_stack

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"

	"git.huangwc.com/pig/pig-farm-controller/internal/app/listener"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/transport"
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/transport/proto"

	gproto "google.golang.org/protobuf/proto"
)

// ChirpStackListener 主动发送的请求的event字段, 这个字段代表事件类型
const (
	eventTypeUp          = "up"          // 上行数据事件：当接收到设备发送的数据时触发，这是最核心的事件。
	eventTypeStatus      = "status"      // 设备状态事件：当设备报告其状态时触发（例如电池电量、信号强度）。
	eventTypeJoin        = "join"        // 入网事件：当设备成功加入网络时触发。
	eventTypeAck         = "ack"         // 下行确认事件：当设备确认收到下行消息时触发。
	eventTypeTxAck       = "txack"       // 网关发送确认事件：当网关确认已发送下行消息时触发（不代表设备已收到）。
	eventTypeLog         = "log"         // 日志事件：当设备或 ChirpStack 产生日志信息时触发。
	eventTypeLocation    = "location"    // 位置事件：当设备的位置被解析或更新时触发。
	eventTypeIntegration = "integration" // 集成事件：当其他集成（如第三方服务）处理数据后触发。
)

// ChirpStackListener 是一个监听器, 用于将ChirpStack的Webhook事件适配到统一的UpstreamHandler。
type ChirpStackListener struct {
	selfCtx context.Context
	handler transport.UpstreamHandler // 依赖注入的统一业务处理器
}

// NewChirpStackListener 创建一个新的 ChirpStackListener 实例。
func NewChirpStackListener(
	ctx context.Context,
	handler transport.UpstreamHandler,
) listener.ListenHandler {
	return &ChirpStackListener{
		selfCtx: logs.AddCompName(ctx, "ChirpStackListener"),
		handler: handler,
	}
}

// Handler 监听ChirpStack反馈的事件, 因为这是个Webhook, 所以直接回复掉再慢慢处理信息
func (c *ChirpStackListener) Handler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 注意：这里的 selfCtx 是 r.Context()，因为它包含了HTTP请求的追踪信息
		ctx, logger := logs.Trace(r.Context(), c.selfCtx, "Handler")

		defer r.Body.Close()

		b, err := io.ReadAll(r.Body)
		if err != nil {
			logger.Errorw("读取请求体失败", "error", err)
			http.Error(w, "failed to read body", http.StatusBadRequest)
			return
		}

		event := r.URL.Query().Get("event")

		w.WriteHeader(http.StatusOK)

		// 使用分离的上下文进行异步处理，防止原始请求取消导致处理中断
		detachedCtx := logs.DetachContext(ctx)
		go c.dispatch(detachedCtx, b, event)
	}
}

// dispatch 用于解析并分发 ChirpStack 发送的事件
func (c *ChirpStackListener) dispatch(ctx context.Context, data []byte, eventType string) {
	reqCtx, logger := logs.Trace(ctx, c.selfCtx, "dispatch")

	var err error
	switch eventType {
	case eventTypeUp:
		var msg UpEvent
		if err = json.Unmarshal(data, &msg); err == nil {
			c.adaptUpEvent(reqCtx, &msg)
		}

	case eventTypeStatus:
		var msg StatusEvent
		if err = json.Unmarshal(data, &msg); err == nil {
			c.adaptStatusEvent(reqCtx, &msg)
		}

	case eventTypeAck:
		var msg AckEvent
		if err = json.Unmarshal(data, &msg); err == nil {
			c.adaptAckEvent(reqCtx, &msg)
		}

	// --- 其他事件只记录日志，不进行业务处理 ---
	case eventTypeJoin, eventTypeTxAck, eventTypeLog, eventTypeLocation, eventTypeIntegration:
		logger.Infow("收到一个非业务处理的ChirpStack事件", "type", eventType)

	default:
		logger.Warnw("未知的ChirpStack事件类型", "type", eventType)
	}

	if err != nil {
		logger.Errorw("解析ChirpStack事件失败", "type", eventType, "error", err, "data", string(data))
	}
}

// --- 适配器函数 ---

// adaptUpEvent 将 'up' 事件适配并委托给 UpstreamHandler
func (c *ChirpStackListener) adaptUpEvent(ctx context.Context, event *UpEvent) {
	reqCtx, logger := logs.Trace(ctx, c.selfCtx, "adaptUpEvent")

	// 1. 优先处理并委托旁路状态信息（如信号强度）
	if len(event.RxInfo) > 0 {
		rx := event.RxInfo[0]
		status := map[string]interface{}{
			"rssi": float64(rx.Rssi),
			"snr":  float64(rx.Snr),
		}
		if err := c.handler.HandleStatus(reqCtx, event.DeviceInfo.DevEui, status); err != nil {
			logger.Errorw("委托 'up' 事件中的状态信息失败", "error", err)
		}
	}

	// 2. 如果没有业务数据，则直接返回
	if event.Data == "" {
		return
	}

	// 3. 解码并解析业务指令
	decodedData, err := base64.StdEncoding.DecodeString(event.Data)
	if err != nil {
		logger.Errorw("Base64解码 'up' 事件的Data失败", "error", err, "data", event.Data)
		return
	}

	var instruction proto.Instruction
	if err := gproto.Unmarshal(decodedData, &instruction); err != nil {
		logger.Errorw("解析上行Instruction Protobuf失败", "error", err, "decodedData", fmt.Sprintf("%x", decodedData))
		return
	}

	// 4. 委托给统一处理器
	if err := c.handler.HandleInstruction(reqCtx, event.DeviceInfo.DevEui, &instruction); err != nil {
		logger.Errorw("委托 'up' 事件中的业务指令失败", "error", err)
	}
}

// adaptStatusEvent 将 'status' 事件适配并委托给 UpstreamHandler
func (c *ChirpStackListener) adaptStatusEvent(ctx context.Context, event *StatusEvent) {
	reqCtx, logger := logs.Trace(ctx, c.selfCtx, "adaptStatusEvent")

	status := map[string]interface{}{
		"margin":                  float64(event.Margin),
		"batteryLevel":            float64(event.BatteryLevel),
		"batteryLevelUnavailable": event.BatteryLevelUnavailable,
		"externalPower":           event.ExternalPower,
	}

	if err := c.handler.HandleStatus(reqCtx, event.DeviceInfo.DevEui, status); err != nil {
		logger.Errorw("委托 'status' 事件失败", "error", err)
	}
}

// adaptAckEvent 将 'ack' 事件适配并委托给 UpstreamHandler
func (c *ChirpStackListener) adaptAckEvent(ctx context.Context, event *AckEvent) {
	reqCtx, logger := logs.Trace(ctx, c.selfCtx, "adaptAckEvent")

	if err := c.handler.HandleAck(reqCtx, event.DeviceInfo.DevEui, event.DeduplicationID, event.Acknowledged, event.Time); err != nil {
		logger.Errorw("委托 'ack' 事件失败", "error", err)
	}
}
