package order

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	"juwan-backend/app/order/api/internal/svc"
	"juwan-backend/app/order/api/internal/types"
	"juwan-backend/app/order/rpc/orderservice"
	"juwan-backend/common/utils/contextj"
)

func int64Ptr(v int64) *int64 {
	return &v
}

func stringPtr(v string) *string {
	return &v
}

func formatUnix(ts int64) string {
	if ts <= 0 {
		return ""
	}
	return time.Unix(ts, 0).UTC().Format(time.RFC3339)
}

func toAPIOrder(in *orderservice.Orders) types.Order {
	order := types.Order{}
	if in == nil {
		return order
	}

	totalPrice, _ := strconv.ParseFloat(in.GetTotalPrice(), 64)
	playerID := strconv.FormatInt(in.GetPlayerId(), 10)
	service := types.PlayerService{}
	_ = json.Unmarshal([]byte(in.GetServiceSnapshot()), &service)

	order = types.Order{
		Id:          in.GetId(),
		ConsumerId:  in.GetConsumerId(),
		PlayerId:    playerID,
		ShopId:      in.GetShopId(),
		Service:     service,
		Status:      in.GetStatus(),
		TotalPrice:  totalPrice,
		Note:        in.GetNote(),
		CreatedAt:   formatUnix(in.GetCreatedAt()),
		AcceptedAt:  formatUnix(in.GetAcceptedAt()),
		CompletedAt: formatUnix(in.GetCompletedAt()),
	}

	return order
}

// validTransitions defines the allowed order state transitions per the API spec.
var validTransitions = map[string][]string{
	"pending_payment": {"pending_accept"},
	"pending_accept":  {"in_progress", "cancelled"},
	"in_progress":     {"pending_close", "disputed"},
	"pending_close":   {"pending_review", "disputed"},
	"pending_review":  {"completed"},
	"disputed":        {"pending_review"},
}

func transitionOrderStatus(ctx context.Context, svcCtx *svc.ServiceContext, orderID int64, toStatus string, setAcceptedAt bool, setClosedAt bool, setCompletedAt bool, setCancelledAt bool) error {
	current, err := svcCtx.OrderRpc.GetOrdersById(ctx, &orderservice.GetOrdersByIdReq{Id: orderID})
	if err != nil {
		return err
	}
	if current.GetOrders() == nil {
		return errors.New("order not found")
	}

	fromStatus := current.Orders.GetStatus()
	allowed, ok := validTransitions[fromStatus]
	if !ok {
		return fmt.Errorf("order status %q does not allow any transition", fromStatus)
	}
	found := false
	for _, s := range allowed {
		if s == toStatus {
			found = true
			break
		}
	}
	if !found {
		return fmt.Errorf("transition from %q to %q is not allowed", fromStatus, toStatus)
	}

	now := time.Now().Unix()
	updateReq := &orderservice.UpdateOrdersReq{
		Id:        orderID,
		Status:    stringPtr(toStatus),
		UpdatedAt: int64Ptr(now),
	}
	if setAcceptedAt {
		updateReq.AcceptedAt = int64Ptr(now)
	}
	if setClosedAt {
		updateReq.ClosedAt = int64Ptr(now)
	}
	if setCompletedAt {
		updateReq.CompletedAt = int64Ptr(now)
	}
	if setCancelledAt {
		updateReq.CancelledAt = int64Ptr(now)
	}

	if _, err = svcCtx.OrderRpc.UpdateOrders(ctx, updateReq); err != nil {
		return err
	}

	actorID, _ := contextj.UserIDFrom(ctx)
	actorRole := "system"
	if actorID > 0 {
		actorRole = "user"
	}
	_, err = svcCtx.OrderRpc.AddOrderStateLogs(ctx, &orderservice.AddOrderStateLogsReq{
		OrderId:    orderID,
		FromStatus: &fromStatus,
		ToStatus:   toStatus,
		Action:     "status_transition",
		ActorId:    actorID,
		ActorRole:  actorRole,
		CreatedAt:  &now,
	})
	if err != nil {
		return err
	}

	return nil
}
