package m9z

import (
	"encoding/binary"
	"fmt"
	"strconv"
	"strings"

	"github.com/gogf/gf/v2/util/gconv"
)

// LoopCommonParameters 回路分控器公共参数结构体 (15个寄存器 = 30字节)
type LoopCommonParameters struct {
	DCVoltage      float32  // 直流电压 (0.1V单位)
	DCCurrent      float32  // 直流电流 (0.001A单位)
	DimmingValue   float32  // 调光幅度值 (0-100%)
	AlarmStatus    uint16   // 告警状态 (位图形式) 告警状态寄存器 0x01欠压 0x02过压 0x08电源故障 其中：欠压＝短路故障，过压＝开路故障，电源故障。
	AlarmCode      string   // 告警代码
	RelayStatus    uint16   // 继电器状态 (位图形式)
	LoopAddress    string   // 回路地址
	SubModuleCount uint16   // 子模块数量
	Reserved       [14]byte // 备用字段 (7个寄存器=14字节)
}

// LoopModuleParameters 回路子模块参数结构体 (13个寄存器 = 26字节)
type LoopModuleParameters struct {
	OutputVoltage      float32 // 模块输出电压值 (0.1V)
	OutputCurrent      float32 // 模块输出电流值 (0.01A)
	CurrentPWMDuty     float32 // 模块电流PWM占空比 (0-10000对应0-100%)
	VoltagePWMDuty     float32 // 模块电压PWM占空比 (0-10000对应0-100%)
	DeviceAddress      string  // 模块的设备地址
	ModuleLoopAddress  string  // 模块的回路地址
	CurrentLimitPct    float32 // 模块的限流百分数 (0-100对应0-100%)
	OperatingMode      uint16  // 模块手动/自动模式 (0=自动,1=手动)
	ModuleVersion      float32 // 模块的版本号
	RatedVoltageDuty   uint16  // 额定配置电压PWM占空比 (0-10000对应0-100%)
	RatedCurrentDuty   uint16  // 额定配置电流PWM占空比 (0-10000对应0-100%)
	RatedOutputVoltage uint16  // 额定配置输出电压值 (0.1V)
	RatedOutputCurrent uint16  // 额定配置输出电流值 (0.01A)
}

// LoopFullParameters 完整回路参数数据结构
type LoopFullParameters struct {
	LoopCommonParameters                        // 公共参数 (30字节)
	Modules              []LoopModuleParameters // 8个模块的参数 (208字节)
}

type LoopFault struct {
	LoopIdx   uint   `json:"loop_idx"`
	DeviceIdx uint   `json:"device_idx,omitempty"`
	Type      string `json:"type"`
	Message   string `json:"message"`
	Code      string `json:"code"`
}

func BuildLoopFaults(loopIdx uint, alarmStatus uint16, alarmCode string) []LoopFault {
	status := byte(alarmStatus)
	if status == 0 {
		return nil
	}

	faults := make([]LoopFault, 0, 3)
	if status&0x01 != 0 {
		faults = append(faults, LoopFault{
			LoopIdx: loopIdx,
			Type:    "short_circuit",
			Message: fmt.Sprintf("回路%d短路故障", loopIdx),
			Code:    "01",
		})
	}
	if status&0x02 != 0 {
		faults = append(faults, LoopFault{
			LoopIdx: loopIdx,
			Type:    "open_circuit",
			Message: fmt.Sprintf("回路%d开路故障", loopIdx),
			Code:    "02",
		})
	}
	if status&0x04 != 0 {
		deviceMask := alarmDeviceMask(alarmCode)
		faults = append(faults, LoopFault{
			LoopIdx: loopIdx,
			Type:    "power",
			Message: buildPowerFaultMessage(loopIdx, deviceMask),
			Code:    fmt.Sprintf("04 %02X", deviceMask),
		})
	}

	if unknownStatus := status &^ 0x07; unknownStatus != 0 {
		faults = append(faults, LoopFault{
			LoopIdx: loopIdx,
			Type:    "unknown",
			Message: fmt.Sprintf("回路%d未知异常", loopIdx),
			Code:    strings.TrimSpace(alarmCode),
		})
	}
	return faults
}

func alarmDeviceMask(alarmCode string) byte {
	fields := strings.Fields(alarmCode)
	if len(fields) < 2 {
		return 0
	}
	value, err := strconv.ParseUint(fields[1], 16, 8)
	if err != nil {
		return 0
	}
	return byte(value)
}

func buildPowerFaultMessage(loopIdx uint, deviceMask byte) string {
	deviceNames := make([]string, 0, 8)
	for i := 0; i < 8; i++ {
		if deviceMask&(1<<i) != 0 {
			deviceNames = append(deviceNames, strconv.Itoa(i+1))
		}
	}
	if len(deviceNames) == 0 {
		return fmt.Sprintf("回路%d电源故障", loopIdx)
	}
	return fmt.Sprintf("回路%d设备%s电源故障", loopIdx, strings.Join(deviceNames, "/"))
}

// ParseLoopFullParameters 解析完整的238字节分控器数据
func ParseLoopFullParameters(data []byte) (*LoopFullParameters, error) {
	if len(data) < 238 {
		return nil, fmt.Errorf("invalid data length %d, expected 238 bytes", len(data))
	}

	params := &LoopFullParameters{}
	offset := 0

	// 解析公共参数区 (30字节)
	common := &params.LoopCommonParameters

	common.DCVoltage = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
	offset += 2
	common.DCCurrent = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.001
	offset += 2
	common.DimmingValue = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01
	offset += 2
	//log.Debugf("AlarmStatus [% X]", data)
	common.AlarmStatus = uint16(data[offset:][0])
	common.AlarmCode = fmt.Sprintf("% X", data[offset:offset+2])
	offset += 2
	common.RelayStatus = binary.LittleEndian.Uint16(data[offset:])
	offset += 2
	if binary.LittleEndian.Uint16(data[offset:]) == 0 {
		return nil, nil
	}
	common.LoopAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:]))

	offset += 2
	common.SubModuleCount = binary.LittleEndian.Uint16(data[offset:])
	offset += 2
	copy(common.Reserved[:], data[offset:offset+16])
	offset += 16
	params.Modules = make([]LoopModuleParameters, common.SubModuleCount)
	// 解析8个模块 (每个26字节)
	for i := 0; i < int(common.SubModuleCount); i++ {
		module := &params.Modules[i]
		module.OutputVoltage = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
		offset += 2
		module.OutputCurrent = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
		offset += 2
		module.CurrentPWMDuty = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01
		offset += 2
		module.VoltagePWMDuty = float32(binary.LittleEndian.Uint16(data[offset:])) * 10 * 0.01
		offset += 2
		module.DeviceAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:]))
		offset += 2
		module.ModuleLoopAddress = fmt.Sprintf("0x%x", binary.LittleEndian.Uint16(data[offset:]))
		offset += 2
		module.CurrentLimitPct = float32(binary.LittleEndian.Uint16(data[offset:])) * 0.1
		offset += 2
		module.OperatingMode = binary.LittleEndian.Uint16(data[offset:])
		offset += 2
		version := fmt.Sprintf("%x", binary.LittleEndian.Uint16(data[offset:]))
		floatVersion := gconv.Float32(version)
		module.ModuleVersion = floatVersion * 0.1
		offset += 2
		module.RatedVoltageDuty = binary.LittleEndian.Uint16(data[offset:])
		offset += 2
		module.RatedCurrentDuty = binary.LittleEndian.Uint16(data[offset:])
		offset += 2
		module.RatedOutputVoltage = binary.LittleEndian.Uint16(data[offset:])
		offset += 2
		module.RatedOutputCurrent = binary.LittleEndian.Uint16(data[offset:])
		offset += 2
	}

	return params, nil
}

func SubLoopParametersRead(device string, idx uint) (*LoopFullParameters, error) {
	readRep, err := ReadCmd(device, subLoopParameters, "读取回路分控器的参数", idx)
	if err != nil {
		return nil, err
	}

	return ParseLoopFullParameters(readRep.Data)
}
