package user

import (
	"context"
	"strconv"
	"time"
)

// ProductInfo 商品简要信息
type ProductInfo struct {
	ID    int64  `json:"id"`
	Name  string `json:"name"`
	Image string `json:"image"`
	Price int64  `json:"price"`
}

type ShipmentGroup struct {
	ExpressCode  string        `json:"express_code"`
	ExpressNo    string        `json:"express_no"`
	BatchNo      string        `json:"batch_no"`
	Status       int32         `json:"status"`
	Count        int64         `json:"count"`
	ShippedAt    *time.Time    `json:"shipped_at,omitempty"`
	ReceivedAt   *time.Time    `json:"received_at,omitempty"`
	InventoryIDs []int64       `json:"inventory_ids"`
	ProductIDs   []int64       `json:"product_ids"`
	Products     []ProductInfo `json:"products"`
}

func (s *service) ListUserShipmentGroups(ctx context.Context, userID int64, page, pageSize int) (items []*ShipmentGroup, total int64, err error) {
	q := s.readDB.ShippingRecords.WithContext(ctx).ReadDB().Where(
		s.readDB.ShippingRecords.UserID.Eq(userID),
		s.readDB.ShippingRecords.Status.Neq(5), // Exclude cancelled records
	)
	total, err = q.Count()
	if err != nil {
		return nil, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}
	rows, err := q.Order(s.readDB.ShippingRecords.UpdatedAt.Desc(), s.readDB.ShippingRecords.ID.Desc()).Offset((page - 1) * pageSize).Limit(pageSize).Find()
	if err != nil {
		return nil, 0, err
	}
	type acc struct {
		status     int32
		shippedAt  *time.Time
		receivedAt *time.Time
		inv        []int64
		pid        []int64
	}
	m := make(map[string]*acc)
	meta := make(map[string]struct{ code, no, batch string })
	order := make([]string, 0) // 保持顺序
	for _, r := range rows {
		// 分组优先级：运单号 > 批次号 > 记录ID
		key := ""
		if r.ExpressNo != "" {
			// 有运单号，按运单号分组
			key = "E|" + r.ExpressCode + "|" + r.ExpressNo
		} else if r.BatchNo != "" {
			// 无运单号但有批次号，按批次号分组
			key = "B|" + r.BatchNo
		} else {
			// 无运单号也无批次号，按记录ID独立
			key = "_" + strconv.FormatInt(r.ID, 10)
		}

		if _, ok := m[key]; !ok {
			m[key] = &acc{}
			meta[key] = struct{ code, no, batch string }{r.ExpressCode, r.ExpressNo, r.BatchNo}
			order = append(order, key)
		}
		a := m[key]
		if a.status == 0 || r.Status >= a.status {
			a.status = r.Status
		}
		if !r.ShippedAt.IsZero() {
			t := r.ShippedAt
			a.shippedAt = &t
		}
		if !r.ReceivedAt.IsZero() {
			t := r.ReceivedAt
			a.receivedAt = &t
		}
		a.inv = append(a.inv, r.InventoryID)
		if r.ProductID > 0 {
			a.pid = append(a.pid, r.ProductID)
		}
	}
	items = make([]*ShipmentGroup, 0, len(m))
	for _, k := range order {
		a := m[k]
		md := meta[k]
		c := int64(len(a.inv))

		// 获取商品详情（去重）
		pidSet := make(map[int64]struct{})
		for _, pid := range a.pid {
			pidSet[pid] = struct{}{}
		}
		products := make([]ProductInfo, 0, len(pidSet))
		for pid := range pidSet {
			if prod, _ := s.readDB.Products.WithContext(ctx).ReadDB().Where(s.readDB.Products.ID.Eq(pid)).First(); prod != nil {
				products = append(products, ProductInfo{
					ID:    prod.ID,
					Name:  prod.Name,
					Image: prod.ImagesJSON,
					Price: prod.Price,
				})
			}
		}

		items = append(items, &ShipmentGroup{
			ExpressCode:  md.code,
			ExpressNo:    md.no,
			BatchNo:      md.batch,
			Status:       a.status,
			Count:        c,
			ShippedAt:    a.shippedAt,
			ReceivedAt:   a.receivedAt,
			InventoryIDs: a.inv,
			ProductIDs:   a.pid,
			Products:     products,
		})
	}
	return items, total, nil
}
