package asset_audit

import (
	"strings"
)

var snapshotFieldSet = map[string]struct{}{
	"id":                {},
	"virtual_no":        {},
	"device_virtual_no": {},
	"iccid":             {},
	"imei":              {},
	"sn":                {},
	"msisdn":            {},
	"shop_id":           {},
	"status":            {},
	"series_id":         {},
	"enable_polling":    {},
	"realname_policy":   {},
	"real_name_status":  {},
	"network_status":    {},
	"stop_reason":       {},
	"deleted":           {},
	"asset_status":      {},
}

// normalizeOperationContent 将原始 before/after 数据归一化为“操作内容”。
// 兼容历史数据：
// 1. 优先读取 operation_content；
// 2. 若 before 仅有资产快照而 after 是操作内容，则按字段名回填 before；
// 3. 若 after 为空则按 before 补齐，保证前端有稳定结构。
func normalizeOperationContent(operationType string, beforeData, afterData map[string]any) (map[string]any, map[string]any) {
	beforeRaw := extractOperationContent(beforeData)
	afterRaw := extractOperationContent(afterData)
	before := trimNonOperationKeys(beforeRaw)
	after := trimNonOperationKeys(afterRaw)
	snapshot := extractAssetSnapshot(beforeData, afterData)

	// 历史数据可能把扁平资产快照直接写到 before_data。
	// 这种情况下 before 不是“操作内容”，需要按 after 字段从快照回填。
	if isLikelySnapshotInsteadOfOperation(before, after, operationType) {
		if len(snapshot) == 0 {
			snapshot = cloneMap(beforeRaw)
		}
		before = deriveBeforeFromSnapshot(after, snapshot)
	}

	if len(before) == 0 && len(after) > 0 {
		before = deriveBeforeFromSnapshot(after, snapshot)
	}
	if len(after) == 0 && len(before) > 0 {
		after = cloneMap(before)
	}

	return before, after
}

// WrapOperationContent 将操作内容包装为统一结构写入 before_data/after_data。
// 写入格式：
//
//	{
//	  "operation_content": {...},
//	  "asset_snapshot": {...} // 可选
//	}
func WrapOperationContent(beforeOperation, afterOperation, snapshot map[string]any) (map[string]any, map[string]any) {
	before := cloneMap(beforeOperation)
	after := cloneMap(afterOperation)

	if len(before) == 0 && len(after) > 0 {
		before = deriveBeforeFromSnapshot(after, snapshot)
	}
	if len(after) == 0 && len(before) > 0 {
		after = cloneMap(before)
	}

	beforeWrapped := map[string]any{
		"operation_content": before,
	}
	afterWrapped := map[string]any{
		"operation_content": after,
	}
	if len(snapshot) > 0 {
		beforeWrapped["asset_snapshot"] = cloneMap(snapshot)
		afterWrapped["asset_snapshot"] = cloneMap(snapshot)
	}
	return beforeWrapped, afterWrapped
}

func extractOperationContent(data map[string]any) map[string]any {
	if len(data) == 0 {
		return nil
	}
	if v, ok := data["operation_content"]; ok {
		if m, ok := toMap(v); ok {
			return cloneMap(m)
		}
	}
	return cloneMap(data)
}

func extractAssetSnapshot(beforeData, afterData map[string]any) map[string]any {
	candidates := []map[string]any{beforeData, afterData}
	for _, data := range candidates {
		if len(data) == 0 {
			continue
		}
		if v, ok := data["asset_snapshot"]; ok {
			if m, ok := toMap(v); ok {
				return cloneMap(m)
			}
		}
		if v, ok := data["device"]; ok {
			if m, ok := toMap(v); ok {
				return cloneMap(m)
			}
		}
		if v, ok := data["card"]; ok {
			if m, ok := toMap(v); ok {
				return cloneMap(m)
			}
		}
		if isLikelyAssetSnapshot(data) {
			return cloneMap(data)
		}
	}
	return nil
}

func trimNonOperationKeys(in map[string]any) map[string]any {
	if len(in) == 0 {
		return nil
	}
	out := cloneMap(in)
	delete(out, "operation_content")
	delete(out, "asset_snapshot")
	delete(out, "operation_context")
	delete(out, "device")
	delete(out, "card")
	delete(out, "cards")
	if len(out) == 0 {
		return nil
	}
	return out
}

func deriveBeforeFromSnapshot(after map[string]any, snapshot map[string]any) map[string]any {
	if len(after) == 0 {
		return nil
	}
	out := make(map[string]any, len(after))
	for key := range after {
		if val, ok := snapshot[key]; ok {
			out[key] = val
			continue
		}
		if alias := snapshotAlias(key); alias != "" {
			if val, ok := snapshot[alias]; ok {
				out[key] = val
				continue
			}
		}
		out[key] = nil
	}
	return out
}

func snapshotAlias(operationField string) string {
	switch operationField {
	case "target_shop_id", "to_shop_id", "source_shop_id", "from_shop_id":
		return "shop_id"
	case "new_status":
		return "status"
	case "new_series_id":
		return "series_id"
	case "new_realname_policy":
		return "realname_policy"
	case "new_enable_polling":
		return "enable_polling"
	case "new_switch_mode":
		return "switch_mode"
	default:
		return ""
	}
}

func cloneMap(in map[string]any) map[string]any {
	if len(in) == 0 {
		return nil
	}
	out := make(map[string]any, len(in))
	for k, v := range in {
		out[k] = v
	}
	return out
}

func toMap(v any) (map[string]any, bool) {
	switch val := v.(type) {
	case map[string]any:
		return val, true
	default:
		return nil, false
	}
}

func isLikelyAssetSnapshot(data map[string]any) bool {
	if len(data) == 0 {
		return false
	}

	snapshotCount := 0
	for key := range data {
		if _, ok := snapshotFieldSet[key]; !ok {
			return false
		}
		snapshotCount++
	}

	return snapshotCount >= 2
}

func isLikelySnapshotInsteadOfOperation(before, after map[string]any, operationType string) bool {
	if len(before) == 0 || len(after) == 0 {
		return false
	}
	if !isLikelyAssetSnapshot(before) {
		return false
	}

	fieldDesc := getOperationFieldDesc(operationType)
	for key := range after {
		if _, ok := fieldDesc[key]; ok {
			return true
		}
		if _, ok := snapshotFieldSet[key]; !ok {
			return true
		}
	}
	return false
}

func getOperationFieldDesc(operationType string) map[string]string {
	common := map[string]string{
		"batch_total":   "批量总数",
		"success_count": "成功数量",
		"fail_count":    "失败数量",
		"failed_items":  "失败明细",
		"reason":        "原因说明",
	}

	switch strings.TrimSpace(operationType) {
	case "card_allocate", "device_allocate":
		return mergeFieldDesc(common, map[string]string{
			"target_shop_id":     "目标店铺ID",
			"target_shop_name":   "目标店铺名称",
			"to_shop_id":         "目标店铺ID",
			"to_shop_name":       "目标店铺名称",
			"device_ids":         "设备ID列表",
			"device_virtual_nos": "设备虚拟号列表",
			"card_ids":           "卡ID列表",
			"iccids":             "卡ICCID列表",
			"selection_type":     "选择方式",
			"new_status":         "变更后状态",
		})
	case "card_recall", "device_recall":
		return mergeFieldDesc(common, map[string]string{
			"source_shop_id":     "来源店铺ID",
			"source_shop_name":   "来源店铺名称",
			"target_shop":        "回收后归属店铺ID（空表示平台库存）",
			"target_shop_name":   "回收后归属店铺名称",
			"device_ids":         "设备ID列表",
			"device_virtual_nos": "设备虚拟号列表",
			"card_ids":           "卡ID列表",
			"iccids":             "卡ICCID列表",
			"selection_type":     "选择方式",
			"new_status":         "变更后状态",
		})
	case "device_bind_card":
		return map[string]string{
			"binding_id":        "绑定记录ID",
			"slot_position":     "插槽位置",
			"device_id":         "设备ID",
			"device_virtual_no": "设备虚拟号",
			"device_imei":       "设备IMEI",
			"iot_card_id":       "卡ID",
			"iccid":             "卡ICCID",
		}
	case "device_unbind_card":
		return map[string]string{
			"binding_id":        "绑定记录ID",
			"device_id":         "设备ID",
			"device_virtual_no": "设备虚拟号",
			"device_imei":       "设备IMEI",
			"iot_card_id":       "卡ID",
			"iccid":             "卡ICCID",
			"unbind":            "是否执行解绑",
		}
	case "device_stop", "device_start":
		return mergeFieldDesc(common, map[string]string{
			"skip_count":   "跳过数量",
			"failed_items": "失败明细（含ICCID与原因）",
		})
	case "card_speed_tier":
		return map[string]string{
			"tier_code":      "固定限速档位编码",
			"tier_name":      "固定限速档位",
			"integration_id": "Gateway 外部交互记录ID",
		}
	case "device_set_wifi":
		return map[string]string{
			"imei":     "设备 IMEI",
			"ssid":     "WiFi 名称",
			"password": "WiFi 密码（脱敏）",
			"enabled":  "WiFi 开关状态",
		}
	case "device_switch_card":
		return map[string]string{
			"device_virtual_no": "设备虚拟号",
			"device_imei":       "设备IMEI",
			"target_iccid":      "目标ICCID",
		}
	case "device_switch_mode":
		return map[string]string{
			"switch_mode": "切卡模式（0自动/1手动）",
		}
	case "device_reboot":
		return map[string]string{
			"action": "设备重启动作",
		}
	case "device_reset":
		return map[string]string{
			"action": "设备恢复出厂动作",
		}
	case "asset_polling_status", "card_polling_status":
		return mergeFieldDesc(common, map[string]string{
			"enable_polling": "轮询开关（true启用/false禁用）",
			"card_ids":       "卡ID列表",
			"iccids":         "卡ICCID列表",
		})
	case "asset_realname_policy", "card_realname_policy":
		return map[string]string{
			"realname_policy": "实名策略（none/before_order/after_order）",
		}
	case "asset_package_expires_at":
		return map[string]string{
			"package_usage_id": "套餐使用记录ID",
			"expires_at":       "套餐过期时间",
			"status":           "套餐状态",
			"status_name":      "套餐状态名称",
		}
	case "asset_package_usage":
		return map[string]string{
			"package_usage_id":    "套餐使用记录ID",
			"data_usage_mb":       "套餐真实已用量(MB)",
			"virtual_used_mb":     "套餐展示已用量(MB)",
			"real_total_mb":       "套餐真实总量(MB)",
			"virtual_total_mb":    "套餐业务停机阈值(MB)",
			"status":              "套餐状态",
			"status_name":         "套餐状态名称",
			"enable_virtual_data": "是否启用虚流量",
		}
	case "card_realname_status":
		return map[string]string{
			"real_name_status": "实名状态（0未实名/1已实名）",
		}
	case "asset_deactivate", "card_delete", "card_batch_delete", "device_delete":
		return mergeFieldDesc(common, map[string]string{
			"asset_status":       "资产状态",
			"deleted":            "是否删除",
			"iccids":             "卡ICCID列表",
			"device_virtual_nos": "设备虚拟号列表",
			"device_imei":        "设备IMEI",
		})
	case "device_import_task_create", "iot_card_import_task_create":
		return map[string]string{
			"batch_no":        "批次号",
			"file_key":        "文件存储键",
			"realname_policy": "实名策略",
			"carrier_id":      "运营商ID（仅卡导入）",
			"card_category":   "卡类型（仅卡导入）",
		}
	default:
		return mergeFieldDesc(common, map[string]string{
			"card_id":            "卡ID",
			"iccid":              "卡ICCID",
			"iccids":             "卡ICCID列表",
			"device_id":          "设备ID",
			"device_virtual_no":  "设备虚拟号",
			"device_virtual_nos": "设备虚拟号列表",
			"device_imei":        "设备IMEI",
			"device_sn":          "设备SN",
			"shop_name":          "店铺名称",
			"target_shop_name":   "目标店铺名称",
			"source_shop_name":   "来源店铺名称",
		})
	}
}

func mergeFieldDesc(base, extra map[string]string) map[string]string {
	out := make(map[string]string, len(base)+len(extra))
	for k, v := range base {
		out[k] = v
	}
	for k, v := range extra {
		out[k] = v
	}
	return out
}
