package order

import (
	"encoding/json"

	"hfb_sys/backend/internal/model"

	"gorm.io/datatypes"
)

func (row orderRow) toAdminDTO() OrderDTO {
	rentedAt := row.RentedAt
	durationHours := orderDurationHours(row.RentalOrder)
	rentAmountCent := row.RentAmountCent
	ownerRentAmountCent := row.OwnerRentAmountCent
	platformFeeCent := row.PlatformFeeCent
	return OrderDTO{
		ID:                        row.ID,
		OrderNo:                   row.OrderNo,
		ListingID:                 row.ListingID,
		ListingNo:                 row.ListingNo,
		AccountID:                 row.AccountID,
		OwnerID:                   row.OwnerID,
		RenterID:                  row.RenterID,
		OwnerPhone:                row.OwnerPhone,
		RenterPhone:               row.RenterPhone,
		Title:                     row.Title,
		ServerRegion:              row.ServerRegion,
		LoginPlatform:             row.LoginPlatform,
		RentedAt:                  rentedAt,
		EstimatedDurationHours:    durationHours,
		PriceRole:                 "admin",
		DisplayAmountCent:         row.RentAmountCent,
		RentAmountCent:            &rentAmountCent,
		OwnerRentAmountCent:       &ownerRentAmountCent,
		DepositAmountCent:         row.DepositAmountCent,
		DepositOriginalAmountCent: effectiveDepositOriginalAmountCent(row.RentalOrder),
		DepositWaivedAmountCent:   row.DepositWaivedAmountCent,
		PlatformFeeCent:           &platformFeeCent,
		AccountSnapshot:           row.AccountSnapshot,
		Status:                    row.Status,
		HandoffStatus:             row.HandoffStatus,
		SettlementStatus:          row.SettlementStatus,
		CreatedAt:                 row.CreatedAt,
		UpdatedAt:                 row.UpdatedAt,
	}
}

func (row orderRow) toDTOForUser(userID uint64) OrderDTO {
	dto := row.toAdminDTO()
	applyOrderPriceView(&dto, row.RentalOrder, userID)
	return dto
}

func effectiveDepositOriginalAmountCent(order model.RentalOrder) int64 {
	if order.DepositOriginalAmountCent > 0 {
		return order.DepositOriginalAmountCent
	}
	return order.DepositAmountCent
}

func toCheckoutAdminDTO(checkout model.OrderCheckout) CheckoutDTO {
	rentAmountCent := checkout.RentAmountCent
	ownerRentAmountCent := checkout.OwnerRentAmountCent
	platformFeeCent := checkout.PlatformFeeCent
	renterRefundAmountCent := checkout.RenterRefundAmountCent
	ownerIncomeAmountCent := checkout.OwnerIncomeAmountCent
	return CheckoutDTO{
		ID:                      checkout.ID,
		OrderID:                 checkout.OrderID,
		InitiatedBy:             checkout.InitiatedBy,
		Status:                  checkout.Status,
		PriceRole:               "admin",
		DisplayAmountCent:       rentAmountCent,
		RentAmountCent:          &rentAmountCent,
		OwnerRentAmountCent:     &ownerRentAmountCent,
		PlatformFeeCent:         &platformFeeCent,
		DepositAmountCent:       checkout.DepositAmountCent,
		ConsumableAmountCent:    checkout.ConsumableAmountCent,
		CoinConsumedM:           checkout.CoinConsumedM,
		OtherAmountCent:         checkout.OtherAmountCent,
		DepositDeductAmountCent: checkout.DepositDeductAmountCent,
		RenterRefundAmountCent:  &renterRefundAmountCent,
		OwnerIncomeAmountCent:   &ownerIncomeAmountCent,
		Content:                 checkout.Content,
		EvidenceURLS:            decodeStringList(checkout.EvidenceURLS),
		OwnerAdjustmentReason:   checkout.OwnerAdjustmentReason,
		OwnerAdjustedAt:         checkout.OwnerAdjustedAt,
		RenterConfirmedAt:       checkout.RenterConfirmedAt,
		RenterRejectedAt:        checkout.RenterRejectedAt,
		CreatedAt:               checkout.CreatedAt,
		UpdatedAt:               checkout.UpdatedAt,
	}
}

func toCheckoutDTOForUser(checkout model.OrderCheckout, userID uint64, order model.RentalOrder) CheckoutDTO {
	dto := toCheckoutAdminDTO(checkout)
	applyCheckoutPriceView(&dto, order, userID)
	return dto
}

func applyOrderPriceView(dto *OrderDTO, order model.RentalOrder, userID uint64) {
	if dto == nil {
		return
	}
	dto.PlatformFeeCent = nil
	switch {
	case userID == order.OwnerID:
		ownerAmountCent := order.OwnerRentAmountCent
		if ownerAmountCent <= 0 {
			ownerAmountCent = order.RentAmountCent
		}
		dto.PriceRole = "owner"
		dto.DisplayAmountCent = ownerAmountCent
		dto.RentAmountCent = nil
		dto.OwnerRentAmountCent = &ownerAmountCent
		sanitizeOrderSnapshot(&dto.AccountSnapshot, "owner")
	case userID == order.RenterID:
		rentAmountCent := order.RentAmountCent
		dto.PriceRole = "renter"
		dto.DisplayAmountCent = rentAmountCent
		dto.RentAmountCent = &rentAmountCent
		dto.OwnerRentAmountCent = nil
		sanitizeOrderSnapshot(&dto.AccountSnapshot, "renter")
	default:
		dto.PriceRole = ""
		dto.DisplayAmountCent = 0
		dto.RentAmountCent = nil
		dto.OwnerRentAmountCent = nil
		sanitizeOrderSnapshot(&dto.AccountSnapshot, "")
	}
}

func applyCheckoutPriceView(dto *CheckoutDTO, order model.RentalOrder, userID uint64) {
	if dto == nil {
		return
	}
	ownerAmountCent := int64(0)
	if dto.OwnerRentAmountCent != nil {
		ownerAmountCent = *dto.OwnerRentAmountCent
	}
	ownerIncomeAmountCent := int64(0)
	if dto.OwnerIncomeAmountCent != nil {
		ownerIncomeAmountCent = *dto.OwnerIncomeAmountCent
	}
	rentAmountCent := int64(0)
	if dto.RentAmountCent != nil {
		rentAmountCent = *dto.RentAmountCent
	}
	renterRefundAmountCent := int64(0)
	if dto.RenterRefundAmountCent != nil {
		renterRefundAmountCent = *dto.RenterRefundAmountCent
	}
	dto.PlatformFeeCent = nil
	dto.RenterRefundAmountCent = nil
	dto.OwnerIncomeAmountCent = nil
	switch {
	case userID == order.OwnerID:
		dto.PriceRole = "owner"
		dto.DisplayAmountCent = ownerAmountCent
		dto.RentAmountCent = nil
		dto.OwnerRentAmountCent = &ownerAmountCent
		dto.OwnerIncomeAmountCent = &ownerIncomeAmountCent
	case userID == order.RenterID:
		dto.PriceRole = "renter"
		dto.DisplayAmountCent = rentAmountCent
		dto.RentAmountCent = &rentAmountCent
		dto.OwnerRentAmountCent = nil
		dto.RenterRefundAmountCent = &renterRefundAmountCent
	default:
		dto.PriceRole = ""
		dto.DisplayAmountCent = 0
		dto.RentAmountCent = nil
		dto.OwnerRentAmountCent = nil
	}
}

func sanitizeOrderSnapshot(snapshot *datatypes.JSON, role string) {
	if snapshot == nil || len(*snapshot) == 0 {
		return
	}
	var payload map[string]any
	if err := json.Unmarshal(*snapshot, &payload); err != nil {
		return
	}
	rawSummary, ok := payload["asset_summary"]
	if !ok {
		return
	}
	var summary map[string]any
	switch typed := rawSummary.(type) {
	case map[string]any:
		summary = typed
	case string:
		if err := json.Unmarshal([]byte(typed), &summary); err != nil {
			return
		}
	default:
		raw, err := json.Marshal(typed)
		if err != nil || json.Unmarshal(raw, &summary) != nil {
			return
		}
	}
	breakdown, _ := summary["price_breakdown"].(map[string]any)
	if role == "owner" && breakdown != nil {
		if sellerRatio := readJSONNumber(breakdown["seller_ratio"]); sellerRatio > 0 {
			summary["publish_ratio"] = sellerRatio
		}
	}
	delete(summary, "price_breakdown")
	payload["asset_summary"] = summary
	raw, err := json.Marshal(payload)
	if err != nil {
		return
	}
	*snapshot = datatypes.JSON(raw)
}

func marshalStringList(items []string) (datatypes.JSON, error) {
	if items == nil {
		items = []string{}
	}
	raw, err := json.Marshal(items)
	return datatypes.JSON(raw), err
}

func decodeStringList(raw datatypes.JSON) []string {
	if len(raw) == 0 {
		return []string{}
	}
	var items []string
	if err := json.Unmarshal(raw, &items); err != nil {
		return []string{}
	}
	return items
}

func makeAccountSnapshot(account model.GameAccount, listing model.RentalListing) (datatypes.JSON, error) {
	payload := map[string]any{
		"listing_id":       listing.ID,
		"listing_no":       listing.ListingNo,
		"account_id":       account.ID,
		"title":            account.Title,
		"game_name":        account.GameName,
		"server_region":    account.ServerRegion,
		"login_platform":   account.LoginPlatform,
		"rank_level":       account.RankLevel,
		"haf_coin_amount":  account.HafCoinAmount,
		"asset_summary":    account.AssetSummary,
		"season_tags":      account.SeasonTags,
		"screenshot_urls":  account.ScreenshotURLS,
		"snapshot_version": 1,
	}
	raw, err := json.Marshal(payload)
	return datatypes.JSON(raw), err
}
