package svc

import (
	"fmt"
	"time"

	"golib/v3/features/mo"
	"golib/v3/infra/ii"
)

// Row 是一个通过 ii.ItemInfo 校验后的 Map. 通常在成功调用 InsertOne 或 InsertMany 时表示已通过校验
// 目前可以通过 Find 或 Unmarshal 来获取或创建 Row 类型的数据
type Row struct {
	itemInfo *ii.ItemInfo
	m        mo.M
}

func (c Row) Raw() mo.M {
	return c.m
}

func (c Row) Any(k string) any {
	return c.m[k]
}

func (c Row) Double(k string) float64 {
	v, _ := c.m[k].(float64)
	return v
}

func (c Row) Strings(k string) string {
	v, _ := c.m[k].(string)
	return v
}

func (c Row) Object(k string) mo.M {
	v, _ := c.m[k].(mo.M)
	return v
	// m, err := c.itemInfo.ConvertObject(c.Raw, k)
	// if err != nil {
	// 	return nil, err
	// }
	// fieldInfo, _ := c.itemInfo.Field(k)
	// subItem := *c.itemInfo
	// subItem.Fields = fieldInfo.Fields
	// return &Row{itemInfo: &subItem, Raw: m}, nil
}

func (c Row) ObjectTo(k string, val any) error {
	v, ok := c.m[k].(mo.M)
	if !ok {
		return fmt.Errorf("field %v not found in Row", k)
	}
	return mo.Decode(v, val)
}

func (c Row) Array(k string) mo.A {
	v, _ := c.m[k].(mo.A)
	return v
}

func (c Row) Binary(k string) mo.Binary {
	v, _ := c.m[k].(mo.Binary)
	return v
}

func (c Row) ObjectID(k string) mo.ObjectID {
	v, ok := c.m[k].(mo.ObjectID)
	if !ok {
		return mo.NilObjectID
	}
	return v
}

func (c Row) Boolean(k string) bool {
	v, _ := c.m[k].(bool)
	return v
}

func (c Row) Date(k string) mo.DateTime {
	v, _ := c.m[k].(mo.DateTime)
	return v
}

func (c Row) Int32(k string) int32 {
	v, _ := c.m[k].(int32)
	return v
}

func (c Row) Int64(k string) int64 {
	v, _ := c.m[k].(int64)
	return v
}

func (c Row) Has(k string) bool {
	v, ok := c.m[k]
	if !ok {
		return false
	}
	return v != nil
}

func (c Row) HasKey(k string) bool {
	_, ok := c.m[k]
	return ok
}

func (c Row) Delete(k string) {
	delete(c.m, k)
}

func (c Row) Range(f func(k string, v any) bool) {
	for k, v := range c.m {
		if !f(k, v) {
			return
		}
	}
}

func (c Row) Set(k string, v any) error {
	if field, ok := c.itemInfo.Field(k); ok {
		if val, err := field.Convert(v); err == nil {
			c.m[k] = val
			return nil
		} else {
			return err
		}
	} else {
		return fmt.Errorf(k + " not found")
	}
}

func (c Row) Get(k string) (any, bool) {
	v, ok := c.m[k]
	return v, ok
}

func (c Row) LastModified() time.Time {
	if last := c.Date(ii.LastModified); last > 0 {
		return last.Time().Local()
	}
	if creat := c.Date(ii.CreationTime); creat > 0 {
		return creat.Time().Local()
	}
	return time.Time{}
}

func (c Row) String() string {
	b, err := mo.MarshalExtJSON(c.m, true, true)
	if err != nil {
		return err.Error()
	}
	return string(b)
}

func (c Row) MarshalText() (text []byte, err error) {
	return mo.MarshalExtJSON(c.m, false, true)
}

func (c Row) MarshalJSON() ([]byte, error) {
	return mo.MarshalExtJSON(c.m, false, true)
}
