package repository

import (
	"context"
	"fmt"

	"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"

	"gorm.io/gorm"
)

// UnitOfWork 定义了工作单元接口，用于抽象事务管理
type UnitOfWork interface {
	// ExecuteInTransaction 在一个数据库事务中执行给定的函数。
	// 如果函数返回错误，事务将被回滚；否则，事务将被提交。
	// tx 参数是当前事务的 GORM DB 实例，应传递给所有仓库方法。
	ExecuteInTransaction(ctx context.Context, fn func(tx *gorm.DB) error) error
}

// gormUnitOfWork 是 UnitOfWork 接口的 GORM 实现
type gormUnitOfWork struct {
	ctx context.Context
	db  *gorm.DB
}

// NewGormUnitOfWork 创建一个新的 gormUnitOfWork 实例
func NewGormUnitOfWork(ctx context.Context, db *gorm.DB) UnitOfWork {
	return &gormUnitOfWork{
		ctx: ctx,
		db:  db,
	}
}

// ExecuteInTransaction 实现了 UnitOfWork 接口的事务执行逻辑
func (u *gormUnitOfWork) ExecuteInTransaction(ctx context.Context, fn func(tx *gorm.DB) error) error {
	uowCtx, logger := logs.Trace(ctx, u.ctx, "ExecuteInTransaction")

	tx := u.db.WithContext(uowCtx).Begin()
	if tx.Error != nil {
		logger.Errorf("开启数据库事务失败: %v", tx.Error) // 记录错误日志
		return fmt.Errorf("开启事务失败: %w", tx.Error)
	}

	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
			logger.Errorf("事务中发生 panic，已回滚: %v", r) // 记录 panic 日志
		} else if tx.Error != nil { // 如果函数执行过程中返回错误，或者事务本身有错误，则回滚
			tx.Rollback()
			logger.Errorf("事务执行失败，已回滚: %v", tx.Error) // 记录错误日志
		}
	}()

	// 执行业务逻辑函数
	if err := fn(tx); err != nil {
		tx.Rollback()
		return err // 返回业务逻辑函数中的错误
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		logger.Errorf("提交数据库事务失败: %v", err) // 记录错误日志
		return fmt.Errorf("提交事务失败: %w", err)
	}

	return nil
}
