package fssql

import (
	"encoding/json"
	"fmt"
	"reflect"

	"gorm.io/gorm"
)

// func MetadataPATCH(tx *gorm.DB, module string, tableStructPointer any, updateMetadata any, rawID int64) error {
// 	stype := reflect.TypeOf(tableStructPointer)
// 	if stype.Kind() == reflect.Pointer {
// 		stype = stype.Elem()
// 	}

// 	updatesql := `UPDATE %s
// 	SET metadata = CASE
// 	  WHEN metadata IS NULL THEN ?
// 	  ELSE JSON_MERGE_PATCH(metadata, ?)
// 	END
// 	WHERE module = '%s' and id = ?;`

// 	var err error
// 	var metadata []byte

// 	switch mdata := updateMetadata.(type) {
// 	case []byte:
// 		metadata = mdata
// 	case string:
// 		metadata = []byte(mdata)
// 	default:
// 		metadata, err = json.Marshal(updateMetadata)
// 		if err != nil {
// 			return err
// 		}
// 	}

// 	updatesql = fmt.Sprintf(updatesql, tx.NamingStrategy.TableName(stype.Name()), module)
// 	logx.Error(updatesql)
// 	err = tx.Exec(updatesql, metadata, metadata, rawID).Error
// 	if err != nil {
// 		return err
// 	}

// 	return nil
// }

// tableStructPointer 表结构 updateMetadata 可以是json的[]byte也可以结构体
func MetadataModulePATCH(tx *gorm.DB, module string, tableStructPointer any, updateMetadata any, WhereKeysCond string, values ...any) error {
	stype := reflect.TypeOf(tableStructPointer)
	if stype.Kind() == reflect.Pointer {
		stype = stype.Elem()
	}
	tname := tx.NamingStrategy.TableName(stype.Name())

	updatesql := `UPDATE %s  
	SET metadata = CASE
	  WHEN metadata IS NULL THEN ?
	  ELSE JSON_MERGE_PATCH(metadata, ?) 
	END
	WHERE module = '%s' and %s;`

	var err error
	var metadata []byte

	switch mdata := updateMetadata.(type) {
	case []byte:
		metadata = mdata
	case string:
		metadata = []byte(mdata)
	default:
		metadata, err = json.Marshal(updateMetadata)
		if err != nil {
			return err
		}
	}

	var args []any

	args = append(args, metadata, metadata)
	args = append(args, values...)

	updatesql = fmt.Sprintf(updatesql, tname, module, WhereKeysCond)
	// logx.Error(updatesql)
	err = tx.Exec(updatesql, args...).Error
	if err != nil {
		return err
	}

	return nil
}

func MetadataResourcePATCH(tx *gorm.DB, rid string, updateMetadata any, values ...any) error {
	// stype := reflect.TypeOf(tableStructPointer)
	// if stype.Kind() == reflect.Pointer {
	// 	stype = stype.Elem()
	// }

	var updatesql string

	if len(values) == 0 {
		updatesql = `UPDATE fs_resource  
		SET metadata = CASE
		  WHEN metadata IS NULL THEN ?
		  ELSE JSON_MERGE_PATCH(metadata, ?) 
		END
		WHERE resource_id = '%s';`
	} else {
		cond, ok := values[0].(string)
		if !ok {
			return fmt.Errorf("values[0] must be wherecond")
		}
		updatesql = `UPDATE fs_resource  
		SET metadata = CASE
		  WHEN metadata IS NULL THEN ?
		  ELSE JSON_MERGE_PATCH(metadata, ?) 
		END
		WHERE resource_id = '%s'` + " and " + cond + `;`
	}

	var err error
	var metadata []byte

	switch mdata := updateMetadata.(type) {
	case []byte:
		metadata = mdata
	case string:
		metadata = []byte(mdata)
	default:
		metadata, err = json.Marshal(updateMetadata)
		if err != nil {
			return err
		}
	}

	var args []any

	args = append(args, metadata, metadata)
	args = append(args, values...)

	updatesql = fmt.Sprintf(updatesql, rid)
	// logx.Error(updatesql)
	err = tx.Exec(updatesql, args...).Error
	if err != nil {
		return err
	}

	return nil
}

func MetadataOrderPATCH(tx *gorm.DB, sql string, orderSn string, tableStructPointer any, updateMetadata any, WhereKeysCond string, values ...any) error {
	stype := reflect.TypeOf(tableStructPointer)
	if stype.Kind() == reflect.Pointer {
		stype = stype.Elem()
	}

	updatesql := `UPDATE %s
	SET metadata = CASE
	  WHEN metadata IS NULL THEN ?
	  ELSE JSON_MERGE_PATCH(metadata, ?)
	END%s
	WHERE order_sn = '%s' and %s;`

	var err error
	var metadata []byte

	switch mdata := updateMetadata.(type) {
	case []byte:
		metadata = mdata
	case string:
		metadata = []byte(mdata)
	default:
		metadata, err = json.Marshal(updateMetadata)
		if err != nil {
			return err
		}
	}

	var args []any

	args = append(args, metadata, metadata)
	args = append(args, values...)

	updatesql = fmt.Sprintf(updatesql, tx.NamingStrategy.TableName(stype.Name()), sql, orderSn, WhereKeysCond)
	// logx.Error(updatesql)
	err = tx.Exec(updatesql, args...).Error
	if err != nil {
		return err
	}

	return nil
}

func GetGormTableName(tx *gorm.DB, tableStructPointer any) string {
	stype := reflect.TypeOf(tableStructPointer)
	if stype.Kind() == reflect.Pointer {
		stype = stype.Elem()
	}
	tname := tx.NamingStrategy.TableName(stype.Name())
	return tname
}