package model

import (
	"encoding/json"
	"strconv"
	"time"

	"gorm.io/gorm"
)

// Device 设备模型
// 物联网设备(如 GPS 追踪器、智能传感器)
// 通过 shop_id 区分所有权：NULL=平台库存，有值=店铺所有
// 标识符说明：virtual_no 为虚拟号/别名，imei/sn 为设备真实标识
type Device struct {
	gorm.Model
	BaseModel                          `gorm:"embedded"`
	VirtualNo                          string     `gorm:"column:virtual_no;type:varchar(100);uniqueIndex:idx_device_virtual_no,where:deleted_at IS NULL;not null;comment:设备虚拟号/别名(用户友好的短标识)" json:"virtual_no"`
	IMEI                               string     `gorm:"column:imei;type:varchar(20);comment:设备IMEI(有蜂窝网络的设备标识,用于Gateway API调用)" json:"imei"`
	SN                                 string     `gorm:"column:sn;type:varchar(100);comment:设备序列号(厂商唯一标识,预留字段)" json:"sn"`
	DeviceName                         string     `gorm:"column:device_name;type:varchar(255);comment:设备名称" json:"device_name"`
	DeviceModel                        string     `gorm:"column:device_model;type:varchar(100);comment:设备型号" json:"device_model"`
	DeviceType                         string     `gorm:"column:device_type;type:varchar(50);comment:设备类型" json:"device_type"`
	MaxSimSlots                        int        `gorm:"column:max_sim_slots;type:int;default:4;comment:最大插槽数量(默认4)" json:"max_sim_slots"`
	Manufacturer                       string     `gorm:"column:manufacturer;type:varchar(255);comment:制造商" json:"manufacturer"`
	BatchNo                            string     `gorm:"column:batch_no;type:varchar(100);comment:批次号" json:"batch_no"`
	ShopID                             *uint      `gorm:"column:shop_id;index;comment:店铺ID(NULL=平台库存,有值=店铺所有)" json:"shop_id,omitempty"`
	Status                             int        `gorm:"column:status;type:int;default:1;not null;comment:归属状态 1-在库 2-已分销" json:"status"`
	ActivatedAt                        *time.Time `gorm:"column:activated_at;comment:激活时间" json:"activated_at"`
	DeviceUsername                     string     `gorm:"column:device_username;type:varchar(100);comment:设备登录用户名" json:"device_username"`
	DevicePasswordEncrypted            string     `gorm:"column:device_password_encrypted;type:varchar(255);comment:设备登录密码(加密)" json:"device_password_encrypted"`
	DeviceAPIEndpoint                  string     `gorm:"column:device_api_endpoint;type:varchar(500);comment:设备API端点" json:"device_api_endpoint"`
	SeriesID                           *uint      `gorm:"column:series_id;index;comment:套餐系列ID(关联PackageSeries)" json:"series_id,omitempty"`
	AccumulatedRechargeBySeriesJSON    string     `gorm:"column:accumulated_recharge_by_series;type:jsonb;default:'{}';comment:按套餐系列追踪的累计充值金额" json:"-"`
	FirstRechargeTriggeredBySeriesJSON string     `gorm:"column:first_recharge_triggered_by_series;type:jsonb;default:'{}';comment:按套餐系列追踪的首充触发状态" json:"-"`
	AssetStatus                        int        `gorm:"column:asset_status;type:int;not null;default:1;comment:业务状态 1-在库 2-已销售 3-已换货 4-已停用" json:"asset_status"`
	Generation                         int        `gorm:"column:generation;type:int;not null;default:1;comment:资产世代编号" json:"generation"`
	// EnablePolling 是否参与轮询，false 时设备下所有卡不加入轮询队列
	EnablePolling bool `gorm:"column:enable_polling;not null;default:true" json:"enable_polling"`
	// 以下字段由 Gateway sync-info 接口同步，有离线存储意义
	OnlineStatus      int        `gorm:"column:online_status;type:int;not null;default:0;comment:在线状态：0未知 1在线 2离线" json:"online_status"`
	LastOnlineTime    *time.Time `gorm:"column:last_online_time;comment:最后在线时间（来自 Gateway sync-info）" json:"last_online_time,omitempty"`
	SoftwareVersion   string     `gorm:"column:software_version;type:varchar(100);not null;default:'';comment:固件版本号" json:"software_version"`
	SwitchMode        string     `gorm:"column:switch_mode;type:varchar(10);not null;default:'0';comment:切卡模式：0=自动 1=手动" json:"switch_mode"`
	LastGatewaySyncAt *time.Time `gorm:"column:last_gateway_sync_at;comment:最后一次 sync-info 同步时间" json:"last_gateway_sync_at,omitempty"`
	RealnamePolicy    string     `gorm:"column:realname_policy;type:varchar(20);default:'after_order';not null;comment:实名认证策略(none=无需实名,before_order=先实名后充值/购买,after_order=先充值/购买后实名)" json:"realname_policy"`
}

// TableName 指定表名
func (Device) TableName() string {
	return "tb_device"
}

func (d *Device) GetAccumulatedRechargeBySeriesMap() (map[uint]int64, error) {
	result := make(map[uint]int64)
	if d.AccumulatedRechargeBySeriesJSON == "" || d.AccumulatedRechargeBySeriesJSON == "{}" {
		return result, nil
	}
	var raw map[string]int64
	if err := json.Unmarshal([]byte(d.AccumulatedRechargeBySeriesJSON), &raw); err != nil {
		return nil, err
	}
	for k, v := range raw {
		id, err := strconv.ParseUint(k, 10, 64)
		if err != nil {
			continue
		}
		result[uint(id)] = v
	}
	return result, nil
}

func (d *Device) SetAccumulatedRechargeBySeriesMap(m map[uint]int64) error {
	raw := make(map[string]int64)
	for k, v := range m {
		raw[strconv.FormatUint(uint64(k), 10)] = v
	}
	data, err := json.Marshal(raw)
	if err != nil {
		return err
	}
	d.AccumulatedRechargeBySeriesJSON = string(data)
	return nil
}

func (d *Device) GetAccumulatedRechargeBySeries(seriesID uint) int64 {
	m, err := d.GetAccumulatedRechargeBySeriesMap()
	if err != nil {
		return 0
	}
	return m[seriesID]
}

func (d *Device) AddAccumulatedRechargeBySeries(seriesID uint, amount int64) error {
	m, err := d.GetAccumulatedRechargeBySeriesMap()
	if err != nil {
		m = make(map[uint]int64)
	}
	m[seriesID] += amount
	return d.SetAccumulatedRechargeBySeriesMap(m)
}

func (d *Device) GetFirstRechargeTriggeredBySeriesMap() (map[uint]bool, error) {
	result := make(map[uint]bool)
	if d.FirstRechargeTriggeredBySeriesJSON == "" || d.FirstRechargeTriggeredBySeriesJSON == "{}" {
		return result, nil
	}
	var raw map[string]bool
	if err := json.Unmarshal([]byte(d.FirstRechargeTriggeredBySeriesJSON), &raw); err != nil {
		return nil, err
	}
	for k, v := range raw {
		id, err := strconv.ParseUint(k, 10, 64)
		if err != nil {
			continue
		}
		result[uint(id)] = v
	}
	return result, nil
}

func (d *Device) SetFirstRechargeTriggeredBySeriesMap(m map[uint]bool) error {
	raw := make(map[string]bool)
	for k, v := range m {
		raw[strconv.FormatUint(uint64(k), 10)] = v
	}
	data, err := json.Marshal(raw)
	if err != nil {
		return err
	}
	d.FirstRechargeTriggeredBySeriesJSON = string(data)
	return nil
}

func (d *Device) IsFirstRechargeTriggeredBySeries(seriesID uint) bool {
	m, err := d.GetFirstRechargeTriggeredBySeriesMap()
	if err != nil {
		return false
	}
	return m[seriesID]
}

func (d *Device) SetFirstRechargeTriggeredBySeries(seriesID uint, triggered bool) error {
	m, err := d.GetFirstRechargeTriggeredBySeriesMap()
	if err != nil {
		m = make(map[uint]bool)
	}
	m[seriesID] = triggered
	return d.SetFirstRechargeTriggeredBySeriesMap(m)
}
