package postgres

import (
	"context"
	"maps"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"gorm.io/gorm"
)

type ExchangeOrderStore struct {
	db *gorm.DB
}

func NewExchangeOrderStore(db *gorm.DB) *ExchangeOrderStore {
	return &ExchangeOrderStore{db: db}
}

func (s *ExchangeOrderStore) Create(ctx context.Context, order *model.ExchangeOrder) error {
	return s.db.WithContext(ctx).Create(order).Error
}

func (s *ExchangeOrderStore) GetByID(ctx context.Context, id uint) (*model.ExchangeOrder, error) {
	var order model.ExchangeOrder
	query := s.db.WithContext(ctx).Where("id = ?", id)
	query = middleware.ApplyShopFilter(ctx, query)
	if err := query.First(&order).Error; err != nil {
		return nil, err
	}
	return &order, nil
}

func (s *ExchangeOrderStore) List(ctx context.Context, filters map[string]any, page, pageSize int) ([]*model.ExchangeOrder, int64, error) {
	var orders []*model.ExchangeOrder
	var total int64

	query := s.db.WithContext(ctx).Model(&model.ExchangeOrder{})
	query = middleware.ApplyShopFilter(ctx, query)

	if status, ok := filters["status"].(int); ok && status > 0 {
		query = query.Where("status = ?", status)
	}
	if identifier, ok := filters["identifier"].(string); ok && identifier != "" {
		like := "%" + identifier + "%"
		query = query.Where("old_asset_identifier LIKE ? OR new_asset_identifier LIKE ?", like, like)
	}
	if createdAtStart, ok := filters["created_at_start"].(time.Time); ok && !createdAtStart.IsZero() {
		query = query.Where("created_at >= ?", createdAtStart)
	}
	if createdAtEnd, ok := filters["created_at_end"].(time.Time); ok && !createdAtEnd.IsZero() {
		query = query.Where("created_at <= ?", createdAtEnd)
	}

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	if page < 1 {
		page = 1
	}
	if pageSize < 1 {
		pageSize = constants.DefaultPageSize
	}
	if pageSize > constants.MaxPageSize {
		pageSize = constants.MaxPageSize
	}

	offset := (page - 1) * pageSize
	if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&orders).Error; err != nil {
		return nil, 0, err
	}

	return orders, total, nil
}

func (s *ExchangeOrderStore) UpdateStatus(ctx context.Context, id uint, fromStatus, toStatus int, updates map[string]any) error {
	values := make(map[string]any, len(updates)+1)
	maps.Copy(values, updates)
	values["status"] = toStatus

	result := s.db.WithContext(ctx).Model(&model.ExchangeOrder{}).
		Where("id = ? AND status = ?", id, fromStatus).
		Updates(values)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}
	return nil
}

// FindByNewAssetID 通过新资产类型和ID查询换货来源记录
// 用于换货链追溯：找到将当前资产作为换货结果的换货单，从而得到前代资产信息
// 若未找到则返回 nil, nil 表示该资产无前代
func (s *ExchangeOrderStore) FindByNewAssetID(ctx context.Context, assetType string, assetID uint) (*model.ExchangeOrder, error) {
	var order model.ExchangeOrder
	err := s.db.WithContext(ctx).
		Where("new_asset_id = ? AND new_asset_type = ?", assetID, assetType).
		Order("id DESC").
		First(&order).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, err
	}
	return &order, nil
}

func (s *ExchangeOrderStore) FindActiveByOldAsset(ctx context.Context, assetType string, assetID uint) (*model.ExchangeOrder, error) {
	var order model.ExchangeOrder
	query := s.db.WithContext(ctx).
		Where("old_asset_type = ? AND old_asset_id = ?", assetType, assetID).
		Where("status IN ?", []int{constants.ExchangeStatusPendingInfo, constants.ExchangeStatusPendingShip, constants.ExchangeStatusShipped})
	query = middleware.ApplyShopFilter(ctx, query)
	if err := query.Order("id DESC").First(&order).Error; err != nil {
		return nil, err
	}
	return &order, nil
}
