package service

import (
	"cold-delivery/app/admin/model"
	"cold-delivery/app/admin/service/dto"
	"cold-delivery/common/actions"
	cDto "cold-delivery/common/dto"
	"cold-delivery/common/global"
	"errors"
	"fmt"

	"gogs.baozhida.cn/zoie/OAuth-core/service"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type Address struct {
	service.Service
}

func AddressNameScopes(name string) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if len(name) == 0 {
			return db
		}
		name = "%" + name + "%"
		return db.Where("phone like ? or address like ? or name like ? ",
			name, name, name)
	}
}

func AddressDataScopes(dataType string, userId int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {

		if dataType == "all" {
			return db
		}
		return db.Where("create_by = ?", userId)
	}
}

// GetPage 获取Address列表
func (e *Address) GetPage(c *dto.AddressGetPageReq, list *[]model.Address, count *int64, p *actions.DataPermission) error {
	var err error
	var data model.Address

	var ad model.AddressDefault
	err = e.Orm.Model(&ad).Where("user_id = ?", p.UserId).First(&ad).Error
	if err != nil && !errors.Is(gorm.ErrRecordNotFound, err) {
		e.Log.Errorf("db error: %s", err)
		return global.GetFailedErr
	}
	if ad.AddressId > 0 {
		err = e.Orm.Model(&data).
			Scopes(
				AddressNameScopes(c.Name),
				actions.Permission(data.TableName(), p),
				//AddressDataScopes(c.DataType, p.UserIds),
				cDto.MakeCondition(c.GetNeedSearch()),
				cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
			).
			Order(fmt.Sprintf("id = %d desc", ad.AddressId)).
			Find(list).Limit(-1).Offset(-1).
			Count(count).Error
	} else {
		err = e.Orm.Model(&data).
			Scopes(
				AddressNameScopes(c.Name),
				actions.Permission(data.TableName(), p),
				//AddressDataScopes(c.DataType, p.UserIds),
				cDto.MakeCondition(c.GetNeedSearch()),
				cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
			).
			Find(list).Limit(-1).Offset(-1).
			Count(count).Error
	}

	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.GetFailedErr
	}

	if *count > 0 {
		if (*list)[0].Id == ad.AddressId {
			(*list)[0].IsDefault = true
		}
	}
	return nil
}

// Get 获取Address对象
func (e *Address) Get(d *dto.AddressGetReq, carInfoModel *model.Address, p *actions.DataPermission) error {

	var ad model.AddressDefault
	err := e.Orm.Model(&ad).Where("user_id = ?", p.UserId).First(&ad).Error
	if err != nil && !errors.Is(gorm.ErrRecordNotFound, err) {
		e.Log.Errorf("db error: %s", err)
		return global.GetFailedErr
	}

	err = e.Orm.
		Scopes(actions.Permission(carInfoModel.TableName(), p)).
		First(carInfoModel, d.GetId()).Error

	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return global.GetNotFoundOrNoPermissionErr
		}
		return global.GetFailedErr
	}

	if ad.AddressId == carInfoModel.Id {
		carInfoModel.IsDefault = true
	}

	return nil
}

// Insert 创建Address对象
func (e *Address) Insert(c *dto.AddressInsertReq) error {
	var err error
	var data model.Address

	tx := e.Orm.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	// 添加地址
	c.Generate(&data)
	err = tx.Create(&data).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.CreateFailedErr
	}
	c.Id = data.Id

	if c.AddressType == model.AddressTypeSender && c.IsDefault == true {
		ad := &model.AddressDefault{UserId: c.CreateBy, AddressId: c.Id}
		//err = tx.Model(&ad).
		//	Where("user_id = ?", c.CreateBy).Update("address_id", c.Id).Error
		//if err != nil {
		//	if errors.Is(gorm.ErrRecordNotFound, err) {
		//		err = tx.Create(&ad).Error
		//		if err != nil {
		//			e.Log.Errorf("db error: %s", err)
		//			return global.CreateFailedErr
		//		}
		//		return nil
		//	}
		//	e.Log.Errorf("db error: %s", err)
		//	return global.CreateFailedErr
		//}
		err = tx.Debug().Clauses(clause.OnConflict{
			Columns: []clause.Column{{Name: "user_id"}},
			//DoUpdates: clause.AssignmentColumns([]string{"address_id"}),
			UpdateAll: true,
		}).Create(&ad).Error
		if err != nil {
			e.Log.Errorf("db error: %s", err)
			return global.CreateFailedErr
		}
	}

	return nil

}

// Update 修改Address对象
func (e *Address) Update(c *dto.AddressUpdateReq, p *actions.DataPermission) error {
	var err error

	tx := e.Orm.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	var ad model.AddressDefault
	err = e.Orm.Model(&ad).Where("user_id = ?", p.UserId).First(&ad).Error
	if err != nil && !errors.Is(gorm.ErrRecordNotFound, err) {
		e.Log.Errorf("db error: %s", err)
		return global.GetFailedErr
	}

	var carInfoModel = model.Address{}
	// 查询地址是否存在
	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
		First(&carInfoModel, c.GetId()).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return global.UpdateNotFoundOrNoPermissionErr
		}
		return global.UpdateFailedErr
	}

	// 默认地址更换
	if c.IsDefault == true && carInfoModel.Id != ad.AddressId && ad.AddressId > 0 {
		err = tx.Model(&model.AddressDefault{}).Where("id = ?", ad.Id).
			Update("address_id", carInfoModel.Id).Error
		if err != nil {
			e.Log.Errorf("db error: %s", err)
			return global.UpdateFailedErr
		}
	}

	// 取消默认地址
	if c.IsDefault == false && carInfoModel.Id == ad.AddressId {
		err = tx.Unscoped().Where("id = ?", ad.Id).Delete(&model.AddressDefault{}).Error
		if err != nil {
			e.Log.Errorf("db error: %s", err)
			return global.UpdateFailedErr
		}
	}

	c.Generate(&carInfoModel)
	err = tx.Save(&carInfoModel).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.UpdateFailedErr
	}

	c.Id = carInfoModel.Id

	return nil
}

// Remove 删除Address
func (e *Address) Remove(c *dto.AddressDeleteReq, p *actions.DataPermission) error {
	var err error

	tx := e.Orm.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	var carInfoModel model.Address

	// 查询地址是否存在
	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
		First(&carInfoModel, c.GetId()).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return global.DeleteNotFoundOrNoPermissionErr
		}
		return global.DeleteFailedErr
	}

	db := tx.Delete(&carInfoModel)

	if err = db.Error; err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.DeleteFailedErr
	}
	if db.RowsAffected == 0 {
		return global.DeleteNotFoundOrNoPermissionErr
	}

	return nil
}
