package courier

import (
	"context"
	"github.com/UpmeshLTD/urus-aio/infrastructure/db/entities"
	"gorm.io/gorm/clause"

	"github.com/UpmeshLTD/urus-aio/shipment/db/gormdb"
)

type Repository interface {
	GetCourier(ctx context.Context, params *entities.GetCourierParams) (*entities.Courier, error)
	GetCouriers(ctx context.Context, params *entities.GetCouriersParams) ([]*entities.Courier, error)
	GetCourierByID(ctx context.Context, id entities.ID) (*entities.Courier, error)
	CreateCourier(ctx context.Context, entity *entities.Courier) (*entities.Courier, error)
	UpdateCourier(ctx context.Context, id entities.ID, entity *entities.Courier) error
	DeleteCourier(ctx context.Context, id entities.ID) error

	GetCouriersByWorkspaceID(ctx context.Context, params *entities.GetSellerCouriersParams) ([]*entities.SellerCourier, error)
	GetSellerCourierByID(ctx context.Context, ID entities.ID) (*entities.SellerCourier, error)
	GetSellerCourier(ctx context.Context, workspaceID string, courierID int64) (*entities.SellerCourier, error)
	CreateSellerCourier(ctx context.Context, entity *entities.SellerCourier) (*entities.SellerCourier, error)
	UpdateSellerCourier(ctx context.Context, id entities.ID, entity *entities.SellerCourier) error
	UpdateSellerCourierStatus(ctx context.Context, id entities.ID, deactivate bool) error
	UpdateSellerCourierVerifyStatus(ctx context.Context, id entities.ID, verified bool) error
	DeleteSellerCourier(ctx context.Context, id entities.ID) error
	SaveSellerCourier(ctx context.Context, entity *entities.SellerCourier) (*entities.SellerCourier, error)
}

type repositoryImpl struct {
	db gormdb.GormDB
}

func NewRepository(db gormdb.GormDB) Repository {
	return &repositoryImpl{
		db: db,
	}
}

func (r *repositoryImpl) GetCourier(ctx context.Context, params *entities.GetCourierParams) (*entities.Courier, error) {
	var (
		result  *entities.Courier
		builder = r.db.DB().Model(&entities.Courier{})
	)

	if params != nil {
		if params.CourierID != 0 {
			builder = builder.Where("id = ?", params.CourierID)
		}
		if params.Code != "" {
			builder = builder.Where("code = ?", params.Code)
		}
	}

	if err := builder.First(&result).Error; err != nil {
		return nil, err
	}
	return result, nil
}

func (r *repositoryImpl) GetCouriers(ctx context.Context, params *entities.GetCouriersParams) ([]*entities.Courier, error) {
	var (
		results []*entities.Courier
		builder = r.db.DB().Model(&entities.Courier{})
	)

	if params != nil {
		if params.CountryID != 0 {
			builder = builder.Where("country_id = ?", params.CountryID)
		}

		if !params.Deactivate {
			builder = builder.Where("deactivate = false")
		}
	}

	if err := builder.Find(&results).Error; err != nil {
		return nil, err
	}
	return results, nil
}

func (r *repositoryImpl) GetCourierByID(ctx context.Context, id entities.ID) (*entities.Courier, error) {
	var err error
	res := &entities.Courier{}

	if err = r.db.DB().First(&res, "id = ?", id.ToInt64()).Error; err != nil {
		return nil, err
	}
	return res, nil
}

func (r *repositoryImpl) CreateCourier(ctx context.Context, entity *entities.Courier) (*entities.Courier, error) {
	if err := r.db.DB().Model(&entities.Courier{}).Create(&entity).Error; err != nil {
		return nil, err
	}

	return entity, nil
}

func (r *repositoryImpl) UpdateCourier(ctx context.Context, id entities.ID, entity *entities.Courier) error {
	if err := r.db.DB().Model(&entities.Courier{}).Where("id = ?", id.ToInt64()).Updates(&entity).Error; err != nil {
		return err
	}

	return nil
}

func (r *repositoryImpl) DeleteCourier(ctx context.Context, id entities.ID) error {
	if err := r.db.DB().Delete(&entities.Courier{}, id).Error; err != nil {
		return err
	}

	return nil
}

func (r *repositoryImpl) GetCouriersByWorkspaceID(ctx context.Context, params *entities.GetSellerCouriersParams) ([]*entities.SellerCourier, error) {
	var (
		res     []*entities.SellerCourier
		builder = r.db.DB().Model(&entities.SellerCourier{}).Preload(clause.Associations)
	)

	builder = builder.Where("workspace_id = ?", params.WorkspaceID)

	if !params.Deactivate {
		builder = builder.Where("deactivate = false")
	}
	if params.Verified {
		builder = builder.Where("verified = true")
	}

	builder = builder.Order("courier_id asc")

	if err := builder.Find(&res).Error; err != nil {
		return nil, err
	}
	return res, nil
}

func (r *repositoryImpl) GetSellerCourier(ctx context.Context, workspaceID string, courierID int64) (*entities.SellerCourier, error) {
	var err error
	var res *entities.SellerCourier

	if err = r.db.DB().Preload(clause.Associations).Where("workspace_id = ? AND courier_id = ?", workspaceID, courierID).First(&res).Error; err != nil {
		return nil, err
	}
	return res, nil
}

func (r *repositoryImpl) CreateSellerCourier(ctx context.Context, entity *entities.SellerCourier) (*entities.SellerCourier, error) {
	if err := r.db.DB().Model(&entities.SellerCourier{}).Create(&entity).Error; err != nil {
		return nil, err
	}
	return entity, nil
}

func (r *repositoryImpl) SaveSellerCourier(ctx context.Context, entity *entities.SellerCourier) (*entities.SellerCourier, error) {
	if err := r.db.DB().Clauses(clause.OnConflict{
		Columns: []clause.Column{{Name: "workspace_id"}, {Name: "courier_id"}},
		TargetWhere: clause.Where{
			Exprs: []clause.Expression{
				clause.Expr{
					SQL: "deleted_at IS NULL",
				},
			},
		},
		UpdateAll: true,
	}).Model(&entities.SellerCourier{}).Create(&entity).Error; err != nil {
		return nil, err
	}
	return entity, nil
}

func (r *repositoryImpl) UpdateSellerCourier(ctx context.Context, id entities.ID, entity *entities.SellerCourier) error {
	return r.db.DB().Model(&entities.SellerCourier{}).Where("id = ?", id.ToInt64()).Updates(&entity).Error
}

func (r *repositoryImpl) UpdateSellerCourierStatus(ctx context.Context, id entities.ID, deactivate bool) error {
	return r.db.DB().Model(&entities.SellerCourier{}).Where("id = ?", id.ToInt64()).Update("deactivate", deactivate).Error
}

func (r *repositoryImpl) UpdateSellerCourierVerifyStatus(ctx context.Context, id entities.ID, verified bool) error {
	return r.db.DB().Model(&entities.SellerCourier{}).Where("id = ?", id.ToInt64()).Update("verified", verified).Error
}

func (r *repositoryImpl) DeleteSellerCourier(ctx context.Context, id entities.ID) error {
	return r.db.DB().Delete(&entities.SellerCourier{}, id).Error
}

func (r *repositoryImpl) GetSellerCourierByID(ctx context.Context, ID entities.ID) (*entities.SellerCourier, error) {
	var result *entities.SellerCourier

	if err := r.db.DB().Model(&entities.SellerCourier{}).Preload(clause.Associations).First(&result, ID).Error; err != nil {
		return nil, err
	}
	return result, nil
}
