package ii

import (
	"regexp"

	"git.simanc.com/software/golib/v4/features/mo"
)

// FieldInfo XML 字段信息
type FieldInfo struct {
	Name     string  `xml:"Name,attr"`     // 数据库字段名称
	Type     mo.Type `xml:"Type,attr"`     // 数据类型
	Required bool    `xml:"Required,attr"` // 是否必填, 默认 false
	Unique   bool    `xml:"Unique,attr"`   // 是否值唯一, 默认值为 false. 设置后此字段会变为唯一值, 并且会设置为索引
	ReadOnly bool    `xml:"ReadOnly,attr"` // 只读, 添加后不会被更新, 即使传入更新字段也会被移除
	// Items 用于 mo.TypeArray, 值为 array 或 object
	// 当值为 array 时数组需要符合 json 数组规范.
	// 值为 object 时则表示数组内的每个元素类型必须为 map[string]interface 类型
	Items FieldItemsType `xml:"Items,attr"`
	// NoField 用于 mo.TypeObject 时无需配置 Fields
	NoField bool `xml:"NoField,attr"`

	// Minimum 和 Maximum 用于 mo.TypeInt32 mo.TypeInt64 mo.TypeDouble mo.TypeDateTime mo.TypeDecimal128
	// 以及 mo.TypeString / mo.TypeArray / mo.TypeObject
	// 数字类型直接用于比较大小
	// mo.TypeString 用于限制字符串最大长度和最小长度
	// mo.TypeArray 用于限制数字最小长度和最大长度
	// mo.TypeObject 用于限制最大字段数量和最小字段数量
	Minimum float64 `xml:"Minimum,attr"` // 最小值
	Maximum float64 `xml:"Maximum,attr"` // 最大值

	Decimal int `xml:"Decimal,attr"` // 保留小数

	// Enums 枚举数据, 当 len(Enums) > 0 时, 此 Field 的值或 Default 必须在其中
	Enums []string `xml:"Enums>Enum"`
	enums []any

	// Fields 适用于 mo.TypeObject 和 mo.TypeArray 的 Items="object"
	Fields []FieldInfo `xml:"Fields>Field"`

	Label string `xml:"Label"` // 中文名称

	Default      string `xml:"Default"` // 默认值, 用于读写时该字段不存在时使用。当默认值不存在时根据 Type 初始化默认值, 例如 int64 类型默认值为 0
	defaultValue any

	// Pattern 适用于 mo.TypeString, 该值为一个正则表达式. 当 Pattern 不为空时会校验此字段的值是否包含在 Pattern 内
	Pattern string `xml:"Pattern"`
	pattern *regexp.Regexp

	// Lookup 关联查询 如果配置了 Fields, 则仅返回已设置的字段
	Lookup []Lookup `xml:"Lookups>Lookup"`

	// SUM 合计数量. 使用 MongoDB Set 聚合实现
	Set []Set `xml:"Sets>Set"`

	Form Form `xml:"Form"`

	fieldMap  map[string]int
	uniqueMap map[string]int // 需要调用 SetUnique 设置唯一键
}

// Lookup 会使用 FieldInfo.Name 的值去关联 From 表中等于 ForeignField 的值的数据, 并将数据存储在 AS 字段中, 值的类型为一个列表 []interface{}
// 但实际使用中可能并不方便, 特在此处自定义 List 开关, 当值为 true 时会返回已查询到的所有数据. 当值为 false 时会返回一条数据(由 MongoDB 决定, 系统未定义). 默认为 false
// 当 AS 值为 [] 时, 无论 List 值为 true 或 false, 也同样返回 []
// 例如使用用户 Id 关联用户名
// 当 FieldInfo.Fields 不为空时则仅返回 FieldInfo.Fields 的字段
type Lookup struct {
	From         string `xml:"From,attr"`         // Lookup.From 数据库表名称. 注意: MongoDB 仅支持当前数据库表的关联, 不支持跨数据库关联
	LocalField   string `xml:"LocalField,attr"`   // Lookup.LocalField 本地字段, 使用 FieldInfo.Name
	ForeignField string `xml:"ForeignField,attr"` // Lookup.ForeignField 远程字段. 需要关联的字段
	AS           string `xml:"As,attr"`           // Lookup.AS 查询后数据存储在此字段内, 请保持此字段在该 ItemInfo 中保持唯一

	List bool   `xml:"List,attr"` // 为 false 时会将数据展开并填充到当前数据内, 每个 key 使用 Lookup.AS 作为前缀
	SUM  string `xml:"SUM,attr"`  // 当 SUM 指定字段时合计数据
}

func (l *Lookup) Valid() bool {
	return l.From != "" && l.ForeignField != "" && l.AS != ""
}

type Set struct {
	Name  string `xml:"Name,attr"`  // 新增字段名称
	OP    string `xml:"OP,attr"`    // 操作, 例如 $sum
	Value string `xml:"Value,attr"` // Set.OP 所需要的值, 根据 Set.OP 变化而变化
}

type Form struct {
	Mode string `xml:"Mode,attr"` // 模式: text/number/select/password

	Unit string `xml:"Unit,attr"` // 单位: RPM Mode=input/number 时有效

	Date     string `xml:"Date,attr"`     // 日期: Mode=text 时有效, date/dateTime/dateTimeSecond/dateRange/dateTimeRange/dateTimeRangeSecond
	Multiple bool   `xml:"Multiple,attr"` // 多选: Mode=select 时有效
	URL      string `xml:"URL,attr"`      // 多选: Mode=select 时有效
	Selected string `xml:"Selected,attr"` // 多选: Mode=select 时有效

	ReadOnly bool `xml:"ReadOnly,attr"` // 表单只读
	Disable  bool `xml:"Disable,attr"`  // 表单禁用

	Help            string `xml:"Help"`            // 帮助
	ValidFeedback   string `xml:"ValidFeedback"`   // 校验成功提示
	InvalidFeedback string `xml:"InvalidFeedback"` // 校验失败提示

	Hidden bool `xml:"Hidden,attr"` // 是否隐藏
}

type FieldInfoJSON struct {
	Name     string          `json:"name"`
	Label    string          `json:"label"`
	Type     string          `json:"type"`
	Required bool            `json:"required"`
	Unique   bool            `json:"unique"`
	Minimum  float64         `json:"minimum"`
	Maximum  float64         `json:"maximum"`
	Decimal  int             `json:"decimal"`
	Default  any             `json:"default"`
	Enums    mo.A            `json:"enums"`
	Pattern  string          `json:"pattern"`
	Fields   []FieldInfoJSON `json:"fields"`
}
