package dataTemp

import (
	"ai_scheduler/utils"
	"context"
	"database/sql"
	"fmt"
	"reflect"

	"github.com/go-kratos/kratos/v2/log"
	"gorm.io/gorm"
	"xorm.io/builder"
)

type PrimaryKey struct {
	Id int `json:"id"`
}

type GormDb struct {
	Client *gorm.DB
}
type contextTxKey struct{}

func (d *Db) DB(ctx context.Context) *gorm.DB {
	tx, ok := ctx.Value(contextTxKey{}).(*gorm.DB)
	if ok {
		return tx
	}
	return d.Db.Client
}

func (t *Db) ExecTx(ctx context.Context, f func(ctx context.Context) error) error {
	return t.Db.Client.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		ctx = context.WithValue(ctx, contextTxKey{}, tx)
		return f(ctx)
	})
}

type Db struct {
	Db  *GormDb
	Log *log.Helper
}

type DataTemp struct {
	Db    *gorm.DB
	Model interface{}
	Do    interface{}
}

func NewDataTemp(db *utils.Db, model interface{}) *DataTemp {
	return &DataTemp{Db: db.Client, Model: model}
}

func (k DataTemp) GetById(id int32) (data map[string]interface{}, err error) {
	err = k.Db.Model(k.Model).Where("id = ?", id).Find(&data).Error
	if data == nil {
		err = sql.ErrNoRows
	}
	return
}

func (k DataTemp) Add(data interface{}) (id int, err error) {

	add := k.Db.Model(k.Model).Create(data)
	return 0, add.Error
}

func (k DataTemp) AddWithData(data interface{}) error {
	result := k.Db.Model(k.Model).Create(data)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

func (k DataTemp) GetList(cond *builder.Cond, pageBoIn *ReqPageBo) (list []map[string]interface{}, pageBoOut *RespPageBo, err error) {
	var (
		query, _ = builder.ToBoundSQL(*cond)
		model    = k.Db.Model(k.Model).Where(query)
		total    int64
	)
	model.Count(&total)
	pageBoOut = pageBoOut.SetDataByReq(total, pageBoIn)
	model.Limit(pageBoIn.GetSize()).Offset(pageBoIn.GetOffset()).Order("updated_at desc").Find(&list)
	return
}

func (k DataTemp) GetRange(cond *builder.Cond) (list []map[string]interface{}, err error) {
	var (
		query, _ = builder.ToBoundSQL(*cond)
		model    = k.Db.Model(k.Model).Where(query)
	)
	err = model.Find(&list).Error
	return list, err
}

func (k DataTemp) GetRangeToMapStruct(cond *builder.Cond, data interface{}) (err error) {
	var (
		query, _ = builder.ToBoundSQL(*cond)
		model    = k.Db.Model(k.Model).Where(query)
	)
	err = model.Find(data).Error
	return err
}

func (k DataTemp) GetOneBySearch(cond *builder.Cond) (data map[string]interface{}, err error) {
	query, _ := builder.ToBoundSQL(*cond)
	err = k.Db.Model(k.Model).Where(query).Limit(1).Find(&data).Error
	if data == nil {
		err = sql.ErrNoRows
	}
	return
}

func (k DataTemp) GetOneBySearchToStrut(cond *builder.Cond, result interface{}) error {
	query, _ := builder.ToBoundSQL(*cond)
	err := k.Db.Model(k.Model).Where(query).Limit(1).Find(&result).Error

	return err
}

func (k DataTemp) GetListToStruct(cond *builder.Cond, pageBoIn *ReqPageBo, result interface{}, orderBy string) (pageBoOut *RespPageBo, err error) {
	var (
		query, _ = builder.ToBoundSQL(*cond)
		model    = k.Db.Model(k.Model).Where(query)
		total    int64
	)
	if len(orderBy) == 0 {
		orderBy = "updated_at desc"
	}
	// 1. 计算总数
	if err = model.Count(&total).Error; err != nil {
		return nil, err
	}

	// 2. 设置分页
	pageBoOut = pageBoOut.SetDataByReq(total, pageBoIn)

	// 3. 查询数据（确保 result 是指针，如 &[]User）
	if err = model.Limit(pageBoIn.GetSize()).
		Offset(pageBoIn.GetOffset()).
		Order(orderBy).
		Find(result).Error; err != nil {
		return nil, err
	}

	// 4. 可选：用 reflect 处理结果（确保类型正确）
	val := reflect.ValueOf(result)
	if val.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("result must be a pointer")
	}

	val = val.Elem() // 解引用
	if val.Kind() == reflect.Slice {
		for i := 0; i < val.Len(); i++ {
			elem := val.Index(i)
			if elem.Kind() == reflect.Struct {
				// 示例：打印某个字段
				if field := elem.FieldByName("ID"); field.IsValid() {
					fmt.Println("ID:", field.Interface())
				}
			}
		}
	}

	return pageBoOut, nil
}

func (k DataTemp) GetListToStruct2(cond *builder.Cond, pageBoIn *ReqPageBo, result interface{}) (pageBoOut *RespPageBo, err error) {
	var (
		query, _ = builder.ToBoundSQL(*cond)
		model    = k.Db.Model(k.Model).Where(query)
		total    int64
	)
	model.Count(&total)
	pageBoOut = pageBoOut.SetDataByReq(total, pageBoIn)
	model.Limit(pageBoIn.GetSize()).Offset(pageBoIn.GetOffset()).Order("updated_at desc").Find(&result)
	return
}

func (k DataTemp) UpdateByCond(cond *builder.Cond, data interface{}) (err error) {
	var (
		query, _ = builder.ToBoundSQL(*cond)
		model    = k.Db.Model(k.Model)
	)
	err = model.Where(query).Updates(data).Error
	return
}

func (k DataTemp) UpdateById(id int32, data interface{}) (err error) {
	err = k.Db.Model(k.Model).Where("id = ?", id).Updates(data).Error

	return
}
