package notificationimp

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"github.com/tech/sendico/pkg/merrors"
	confirmations "github.com/tech/sendico/pkg/messaging/notifications/confirmations"
	"github.com/tech/sendico/pkg/model"
	"github.com/tech/sendico/pkg/mservice"
	"go.uber.org/zap"
)

func (a *NotificationAPI) onConfirmationRequest(ctx context.Context, request *model.ConfirmationRequest) error {
	if request == nil {
		return merrors.InvalidArgument("confirmation request is nil", "request")
	}
	if a == nil || a.tg == nil {
		return merrors.Internal("telegram client is not configured")
	}
	req := normalizeConfirmationRequest(*request)
	if req.RequestID == "" {
		return merrors.InvalidArgument("confirmation request_id is required", "request_id")
	}
	if req.TargetChatID == "" {
		return merrors.InvalidArgument("confirmation target_chat_id is required", "target_chat_id")
	}
	if req.RequestedMoney == nil || strings.TrimSpace(req.RequestedMoney.Amount) == "" || strings.TrimSpace(req.RequestedMoney.Currency) == "" {
		return merrors.InvalidArgument("confirmation requested_money is required", "requested_money")
	}
	if req.SourceService == "" {
		return merrors.InvalidArgument("confirmation source_service is required", "source_service")
	}

	prompt := confirmationPrompt(&req)
	sent, err := a.tg.SendText(ctx, req.TargetChatID, prompt, "")
	if err != nil {
		a.logger.Warn("Failed to send confirmation prompt to Telegram", zap.Error(err), zap.String("request_id", req.RequestID), zap.String("chat_id", req.TargetChatID))
		return err
	}
	if sent == nil || strings.TrimSpace(sent.MessageID) == "" {
		return merrors.Internal("telegram confirmation message id is missing")
	}
	a.logger.Info("Telegram confirmation prompt sent",
		zap.String("request_id", req.RequestID),
		zap.String("chat_id", req.TargetChatID),
		zap.String("message_id", strings.TrimSpace(sent.MessageID)))

	if a.producer == nil {
		return merrors.Internal("messaging producer is not configured")
	}
	dispatch := &model.ConfirmationRequestDispatch{
		RequestID:     req.RequestID,
		ChatID:        req.TargetChatID,
		MessageID:     strings.TrimSpace(sent.MessageID),
		SourceService: req.SourceService,
		Rail:          req.Rail,
	}
	env := confirmations.ConfirmationDispatch(mservice.Notifications, dispatch, req.SourceService, req.Rail)
	if err := a.producer.SendMessage(env); err != nil {
		a.logger.Warn("Failed to publish confirmation dispatch", zap.Error(err), zap.String("request_id", req.RequestID), zap.String("message_id", dispatch.MessageID))
		return err
	}
	return nil
}

func (a *NotificationAPI) onTelegramText(ctx context.Context, request *model.TelegramTextRequest) error {
	if request == nil {
		return merrors.InvalidArgument("telegram text request is nil", "request")
	}
	if a == nil || a.tg == nil {
		return merrors.Internal("telegram client is not configured")
	}
	request.ChatID = strings.TrimSpace(request.ChatID)
	request.ReplyToMessageID = strings.TrimSpace(request.ReplyToMessageID)
	request.Text = strings.TrimSpace(request.Text)
	if request.ChatID == "" {
		return merrors.InvalidArgument("telegram chat_id is required", "chat_id")
	}
	if request.Text == "" {
		return merrors.InvalidArgument("telegram text is required", "text")
	}
	if _, err := a.tg.SendText(ctx, request.ChatID, request.Text, request.ReplyToMessageID); err != nil {
		a.logger.Warn("Failed to send telegram text", zap.Error(err),
			zap.String("request_id", request.RequestID),
			zap.String("chat_id", request.ChatID),
			zap.String("reply_to_message_id", request.ReplyToMessageID))
		return err
	}
	return nil
}

func normalizeConfirmationRequest(request model.ConfirmationRequest) model.ConfirmationRequest {
	request.RequestID = strings.TrimSpace(request.RequestID)
	request.TargetChatID = strings.TrimSpace(request.TargetChatID)
	request.PaymentIntentID = strings.TrimSpace(request.PaymentIntentID)
	request.QuoteRef = strings.TrimSpace(request.QuoteRef)
	request.SourceService = strings.TrimSpace(request.SourceService)
	request.Rail = strings.TrimSpace(request.Rail)
	request.AcceptedUserIDs = normalizeStringList(request.AcceptedUserIDs)
	if request.RequestedMoney != nil {
		request.RequestedMoney.Amount = strings.TrimSpace(request.RequestedMoney.Amount)
		request.RequestedMoney.Currency = strings.TrimSpace(request.RequestedMoney.Currency)
	}
	return request
}

func normalizeStringList(values []string) []string {
	if len(values) == 0 {
		return nil
	}
	result := make([]string, 0, len(values))
	seen := map[string]struct{}{}
	for _, value := range values {
		value = strings.TrimSpace(value)
		if value == "" {
			continue
		}
		if _, ok := seen[value]; ok {
			continue
		}
		seen[value] = struct{}{}
		result = append(result, value)
	}
	if len(result) == 0 {
		return nil
	}
	return result
}

func confirmationPrompt(req *model.ConfirmationRequest) string {
	var builder strings.Builder
	builder.WriteString("Payment confirmation required\n")
	if req.QuoteRef != "" {
		builder.WriteString("Quote ref: ")
		builder.WriteString(req.QuoteRef)
		builder.WriteString("\n")
	}
	if req.RequestedMoney != nil {
		amountFloat, err := strconv.ParseFloat(req.RequestedMoney.Amount, 64)
		if err != nil {
			amountFloat = 0
		}
		_, _ = fmt.Fprintf(&builder, "\n*Requested: %.2f %s*\n\n", amountFloat, req.RequestedMoney.Currency)
	}
	builder.WriteString("Reply with \"<amount> <currency>\" (e.g., 12.34 USD).")
	return builder.String()
}
