package subscriber

import (
	"context"
	"encoding/json"
	"time"

	"github.com/charmingruby/homunc/apps/fraud/internal/fraud/service"
	"github.com/charmingruby/homunc/apps/fraud/pkg/telemetry"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/trace"
)

type OnCheckoutInitiatedMessage struct {
	SessionID   string    `json:"sessionId"`
	UserID      string    `json:"userId"`
	Country     string    `json:"country"`
	Amount      int       `json:"amount"`
	TriggeredAt time.Time `json:"triggeredAt"`
}

func (s *Subscriber) onCheckoutInitiated(ctx context.Context, msg []byte) error {
	ctx, span := telemetry.Tracer.Start(ctx, "Subscriber.OnCheckoutInitiated")
	defer span.End()

	spanCtx := trace.SpanContextFromContext(ctx)

	enrichedLogger := telemetry.Log.With(
		"trace_id", spanCtx.TraceID().String(),
		"span_id", spanCtx.SpanID().String(),
	)

	span.SetAttributes(
		attribute.String("message.topic", "checkouts.initiated"),
		attribute.String("message.raw_payload", string(msg)),
	)

	enrichedLogger.Debug(
		"message received",
		"raw_message", string(msg),
	)

	var data OnCheckoutInitiatedMessage

	unmarshalCtx, unmarshalSpan := telemetry.Tracer.Start(ctx, "Subscriber.OnCheckoutInitiated.MessageUnmarshal")
	defer unmarshalSpan.End()

	if err := json.Unmarshal(msg, &data); err != nil {
		unmarshalSpan.RecordError(err)
		unmarshalSpan.SetStatus(codes.Error, "Failed to unmarshal message")

		spanUnmarshalCtx := trace.SpanContextFromContext(unmarshalCtx)

		telemetry.Log.With(
			"trace_id", spanUnmarshalCtx.TraceID().String(),
			"span_id", spanUnmarshalCtx.SpanID().String(),
		).Error("failed to unmarshal message", "error", err)

		return err
	}

	span.SetAttributes(
		attribute.String("checkout.session_id", data.SessionID),
		attribute.String("checkout.user_id", data.UserID),
		attribute.String("checkout.country", data.Country),
		attribute.Int("checkout.amount", data.Amount),
		attribute.String("checkout.triggered_at", data.TriggeredAt.Format(time.RFC3339Nano)),
	)

	checkTransferCtx, checkTransferSpan := telemetry.Tracer.Start(ctx, "FraudService.CheckTransferAvailability")
	defer checkTransferSpan.End()

	if err := s.service.CheckTransferAvailability(ctx, service.CheckTransferAvailabilityInput{
		SessionID:   data.SessionID,
		UserID:      data.UserID,
		Country:     data.Country,
		Amount:      data.Amount,
		TriggeredAt: data.TriggeredAt,
	}); err != nil {
		checkTransferSpan.RecordError(err)
		checkTransferSpan.SetStatus(codes.Error, "Failed to check transfer availability")

		spanServiceCtx := trace.SpanContextFromContext(checkTransferCtx)
		telemetry.Log.With(
			"trace_id", spanServiceCtx.TraceID().String(),
			"span_id", spanServiceCtx.SpanID().String(),
		).Error("failed to check transfer availability", "error", err)

		return err
	}

	span.SetStatus(codes.Ok, "Message processed successfully")

	enrichedLogger.Debug("message processed successfully")

	return nil
}
