package sqlc

import (
	"context"
	"fmt"

	"github.com/jackc/pgx/v5/pgxpool"

	"route256/loms/internal/domain/entity"
	"route256/loms/internal/domain/model"
	"route256/loms/internal/domain/service"
	"route256/loms/internal/infra/postgres"
)

type orderRepo struct {
	pool *pgxpool.Pool
}

func NewOrderRepository(pool *pgxpool.Pool) service.OrderRepository {
	return &orderRepo{
		pool: pool,
	}
}

func (o *orderRepo) GetQuerier(ctx context.Context) *Queries {
	tx, ok := postgres.TxFromCtx(ctx)
	if ok {
		return New(tx)
	}

	return New(o.pool)
}

func (o *orderRepo) OrderCreate(ctx context.Context, order *entity.Order) (entity.ID, error) {
	querier := o.GetQuerier(ctx)

	id, err := querier.OrderCreate(ctx, &OrderCreateParams{
		StatusName: order.Status,
		UserID:     int64(order.UserID),
	})
	if err != nil {
		return 0, fmt.Errorf("querier.OrderCreate: %w", err)
	}

	for _, item := range order.Items {
		if err := querier.OrderAddItem(ctx, &OrderAddItemParams{
			OrderID: id,
			Sku:     int64(item.ID),
			Count:   int64(item.Count),
		}); err != nil {
			return 0, fmt.Errorf("querier.OrderAddItem: %w", err)
		}
	}

	return entity.ID(id), nil
}

func (o *orderRepo) OrderGetByID(ctx context.Context, orderID entity.ID) (*entity.Order, error) {
	querier := o.GetQuerier(ctx)

	rows, err := querier.OrderGetByID(ctx, int64(orderID))
	if err != nil {
		return nil, fmt.Errorf("querier.OrderGetByID: %w", err)
	}

	if len(rows) == 0 {
		return nil, model.ErrOrderNotFound
	}

	items := make([]entity.OrderItem, len(rows))
	for i, row := range rows {
		items[i] = entity.OrderItem{
			ID: entity.Sku(*row.Sku),
			//nolint:gosec // will not overflow, uint32 is stored as int64
			Count: uint32(*row.Count),
		}
	}

	order := &entity.Order{
		OrderID: orderID,
		Status:  rows[0].Status,
		UserID:  entity.ID(rows[0].UserID),
		Items:   items,
	}

	return order, nil
}

func (o *orderRepo) OrderSetStatus(ctx context.Context, orderID entity.ID, newStatus string) error {
	querier := o.GetQuerier(ctx)

	rows, err := querier.OrderSetStatus(ctx, &OrderSetStatusParams{
		ID:         int64(orderID),
		StatusName: newStatus,
	})
	if err != nil {
		return fmt.Errorf("querier.OrderSetStatus: %w", err)
	}

	if rows == 0 {
		return model.ErrOrderNotFound
	}

	return nil
}
