package order

import (
	"time"

	"hfb_sys/backend/internal/model"
	"hfb_sys/backend/internal/modules/notification"
	"hfb_sys/backend/internal/modules/wallet"

	"gorm.io/gorm"
)

func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, checkout *model.OrderCheckout, renterContent string) (*refundAction, error) {
	listing, account, err := r.lockListingAccountForOrder(tx, order)
	if err != nil {
		return nil, err
	}
	now := time.Now()
	order.Status = orderStatusCompleted
	order.HandoffStatus = handoffStatusReturned
	order.SettlementStatus = settlementStatusSettled
	order.SettledAt = &now
	order.OwnerSettledAt = &now
	completeAssets(listing, account)

	settlement := buildCheckoutSettlement(*order, checkout)
	if err := appendCheckoutOwnerIncome(tx, order, settlement); err != nil {
		return nil, err
	}
	refund, err := r.prepareCheckoutRefund(order, settlement)
	if err != nil {
		return nil, err
	}
	applyCheckoutSettlement(checkout, settlement)
	if err := appendCheckoutCompletedNotifications(tx, order, renterContent); err != nil {
		return nil, err
	}
	if err := saveFinalizedCheckout(tx, order, checkout, listing, account); err != nil {
		return nil, err
	}

	return refund, nil
}

func appendCheckoutOwnerIncome(tx *gorm.DB, order *model.RentalOrder, settlement checkoutSettlement) error {
	orderID := order.ID
	var ownerEntries []wallet.Entry
	if settlement.OwnerRentIncomeCent > 0 {
		ownerEntries = append(ownerEntries, wallet.Entry{
			UserID:      order.OwnerID,
			OrderID:     &orderID,
			Direction:   "in",
			AmountCent:  settlement.OwnerRentIncomeCent,
			BalanceType: "available",
			BizType:     walletBizOwnerIncome,
			BizNo:       order.OrderNo,
			Remark:      "订单结账租金收入",
		})
	}
	if settlement.DepositCompensationCent > 0 {
		ownerEntries = append(ownerEntries, wallet.Entry{
			UserID:      order.OwnerID,
			OrderID:     &orderID,
			Direction:   "in",
			AmountCent:  settlement.DepositCompensationCent,
			BalanceType: "available",
			BizType:     walletBizDepositCompensation,
			BizNo:       order.OrderNo,
			Remark:      "订单结账押金赔付",
		})
	}
	if len(ownerEntries) == 0 {
		return nil
	}
	return wallet.AppendEntries(tx, ownerEntries...)
}

func (r *Repository) prepareCheckoutRefund(order *model.RentalOrder, settlement checkoutSettlement) (*refundAction, error) {
	renterRefundTotalCent := settlement.RentRefundCent + settlement.DepositRefundCent
	// 押金暂扣：若订单已暂扣，拦截本次结账中应退还租客的押金部分挂起不退，其余（租金退款）照常原路退。
	actualRefundCent := order.ApplyDepositHold(renterRefundTotalCent, settlement.DepositRefundCent)
	if actualRefundCent <= 0 {
		return nil, nil
	}
	return r.prepareRefund(order, actualRefundCent, refundBizCheckout, "结账退款原路退还")
}

func applyCheckoutSettlement(checkout *model.OrderCheckout, settlement checkoutSettlement) {
	checkout.RentAmountCent = settlement.ActualRentAmountCent
	checkout.OwnerRentAmountCent = settlement.OwnerRentIncomeCent
	checkout.PlatformFeeCent = settlement.PlatformFeeCent
	checkout.RenterRefundAmountCent = settlement.RenterRefundCent
	checkout.OwnerIncomeAmountCent = settlement.OwnerIncomeCent
}

func appendCheckoutCompletedNotifications(tx *gorm.DB, order *model.RentalOrder, renterContent string) error {
	orderID := order.ID
	return notification.Append(tx,
		notification.Entry{
			UserID:  order.RenterID,
			Type:    "settlement",
			Title:   "订单已完成",
			Content: renterContent,
			BizType: "order",
			BizID:   &orderID,
		},
		notification.Entry{
			UserID:  order.OwnerID,
			Type:    "settlement",
			Title:   "订单已完成",
			Content: "订单已完成，结账金额已入账。",
			BizType: "order",
			BizID:   &orderID,
		},
	)
}

func saveFinalizedCheckout(tx *gorm.DB, order *model.RentalOrder, checkout *model.OrderCheckout, listing *model.RentalListing, account *model.GameAccount) error {
	if err := tx.Save(order).Error; err != nil {
		return err
	}
	if err := tx.Save(checkout).Error; err != nil {
		return err
	}
	if err := tx.Save(listing).Error; err != nil {
		return err
	}
	return tx.Save(account).Error
}

func hasOpenCheckout(tx *gorm.DB, orderID uint64) (bool, error) {
	var count int64
	err := tx.Model(&model.OrderCheckout{}).
		Where("order_id = ? AND status IN ?", orderID, []string{checkoutStatusSubmitted, checkoutStatusCountered, checkoutStatusAccepted, checkoutStatusDisputed}).
		Count(&count).Error
	return count > 0, err
}
