package models

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"strconv"
	"strings"
)

// GetAllModels 返回一个包含所有数据库模型实例的切片。
// 这个函数用于在数据库初始化时自动迁移所有的表结构。
func GetAllModels() []interface{} {
	return []interface{}{
		// Core Models
		&User{},
		&UserActionLog{},

		// Device Models
		&Device{},
		&AreaController{},
		&DeviceTemplate{},
		&SensorData{},
		&DeviceCommandLog{},

		// Plan & Task Models
		&Plan{},
		&SubPlan{},
		&Task{},
		&PlanExecutionLog{},
		&TaskExecutionLog{},
		&PendingTask{},
		&PendingCollection{},

		// Farm Asset Models
		&PigHouse{},
		&Pen{},

		// Pig & Batch Models
		&PigBatch{},
		&PigBatchLog{},
		&WeighingBatch{},
		&WeighingRecord{},
		&PigTransferLog{},
		&PigSickLog{},

		// Pig Buy & Sell
		&PigPurchase{},
		&PigSale{},

		// Feed Models
		&RawMaterial{},
		&RawMaterialPurchase{},
		&RawMaterialStockLog{},
		&FeedFormula{},
		&FeedFormulaComponent{},
		&FeedUsageRecord{},

		// Medication Models
		&Medication{},
		&MedicationLog{},

		// Notification Models
		&Notification{},
	}
}

// UintArray 是一个自定义类型，代表 uint 的切片。
// 它实现了 gorm.Scanner 和 driver.Valuer 接口，
// 以便能与数据库的 bigint[] 类型进行原生映射。
type UintArray []uint

// Value 实现了 driver.Valuer 接口。
// 它告诉 GORM 如何将 UintArray ([]) 转换为数据库能够理解的格式。
func (a UintArray) Value() (driver.Value, error) {
	if a == nil {
		return "{}", nil
	}

	var b strings.Builder
	b.WriteString("{")
	for i, v := range a {
		if i > 0 {
			b.WriteString(",")
		}
		b.WriteString(strconv.FormatUint(uint64(v), 10))
	}
	b.WriteString("}")
	return b.String(), nil
}

// Scan 实现了 gorm.Scanner 接口。
// 它告诉 GORM 如何将从数据库读取的数据转换为我们的 UintArray ([])。
func (a *UintArray) Scan(src interface{}) error {
	if src == nil {
		*a = nil
		return nil
	}

	var srcStr string
	switch v := src.(type) {
	case []byte:
		srcStr = string(v)
	case string:
		srcStr = v
	default:
		return errors.New("无法扫描非字符串或字节类型的源到 UintArray")
	}

	// 去掉花括号
	srcStr = strings.Trim(srcStr, "{}")
	if srcStr == "" {
		*a = []uint{}
		return nil
	}

	// 按逗号分割
	parts := strings.Split(srcStr, ",")
	arr := make([]uint, len(parts))
	for i, p := range parts {
		val, err := strconv.ParseUint(p, 10, 64)
		if err != nil {
			return fmt.Errorf("解析 UintArray 元素失败: %w", err)
		}
		arr[i] = uint(val)
	}

	*a = arr
	return nil
}
