package services

import (
	"strings"
	"time"

	"go.mau.fi/whatsmeow/proto/waE2E"
	"go.mau.fi/whatsmeow/types"
	"go.mau.fi/whatsmeow/types/events"
)

// Old persisted jobs contain a conclusion about the primary phone that a
// timeout cannot prove. Correct presentation without modifying stored history.
func normalizeHistorySyncError(message string) string {
	if strings.Contains(message, "Perangkat tertaut tetap online, tetapi HP utama belum mengirim paket riwayat") {
		return historySyncTimeoutMessage
	}
	return message
}

func (w *waInstance) handleHistoryPeerResponse(event *events.Message) bool {
	if event == nil || !event.Info.IsFromMe || event.Info.Category != "peer" {
		return false
	}
	response := unwrapHistoryMessage(event.Message).GetProtocolMessage().GetPeerDataOperationRequestResponseMessage()
	if response == nil || response.GetPeerDataOperationRequestType() != waE2E.PeerDataOperationRequestType_FULL_HISTORY_SYNC_ON_DEMAND {
		return false
	}
	for _, result := range response.GetPeerDataOperationResult() {
		full := result.GetFullHistorySyncOnDemandRequestResponse()
		if full == nil || full.ResponseCode == nil {
			continue
		}
		requestID := full.GetRequestMetadata().GetRequestID()
		w.mu.Lock()
		if requestID == "" || requestID != w.historyFullRequestID {
			w.mu.Unlock()
			continue
		}
		code := full.GetResponseCode()
		w.historyStatus.ResponseCode = code.String()
		if code == waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_REQUEST_SUCCESS {
			w.mu.Unlock()
			continue
		}
		message := "WhatsApp mengembalikan kesalahan saat menyediakan riwayat."
		switch code {
		case waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_ERROR_REQUEST_ON_NON_SMB_PRIMARY:
			message = "WhatsApp menyatakan akun ini tidak mendukung permintaan riwayat penuh tersebut. Riwayat yang tersedia tetap ditampilkan."
		case waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_DECLINED_SHARING_HISTORY:
			message = "WhatsApp menolak berbagi riwayat untuk permintaan ini. Riwayat yang sudah tersimpan tetap tersedia."
		case waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_REQUEST_TIME_EXPIRED:
			message = "WhatsApp menyatakan permintaan riwayat sudah kedaluwarsa. Silakan buat permintaan baru."
		case waE2E.PeerDataOperationRequestResponseMessage_PeerDataOperationResult_ERROR_HOSTED_DEVICE_NOT_CONNECTED:
			message = "Riwayat penuh belum tersedia melalui koneksi WhatsApp ini. Riwayat yang sudah tersimpan tetap ditampilkan."
		}
		w.historyStatus.State = "failed"
		w.historyStatus.Error = message
		sender := w.historyStatus.Sender
		w.mu.Unlock()
		w.notifyHistoryChatState(sender)
	}
	return true
}

// Aggregate evidence only: no contact IDs, message text or protocol keys.
type HistoryResponseDiagnostics struct {
	Messages            int       `json:"messages"`
	CallMessages        int       `json:"call_messages"`
	PinEvents           int       `json:"pin_events"`
	PinUpdates          int       `json:"pin_updates"`
	PinRejected         int       `json:"pin_rejected"`
	PinStubs            int       `json:"pin_stubs"`
	ReceivedAt          time.Time `json:"received_at"`
	Mode                string    `json:"mode"`
	Conversations       int       `json:"conversations"`
	CallRecords         int       `json:"call_records"`
	CallRecordsAccepted int       `json:"call_records_accepted"`
	MatchedRequest      bool      `json:"matched_request"`
}

func (w *waInstance) historyChunkMatchesRequest(event *events.HistorySync) (active, matched bool, sender string) {
	w.mu.Lock()
	fullID, peerID := w.historyFullRequestID, w.historyPeerRequestID
	sender = w.historyStatus.Sender
	w.mu.Unlock()
	active = fullID != "" || peerID != ""
	if !active {
		return
	}
	fullResponseID := event.Notification.GetFullHistorySyncOnDemandRequestMetadata().GetRequestID()
	if fullID != "" {
		return true, fullResponseID == fullID, sender
	}
	if fullResponseID != "" {
		return true, false, sender
	}
	originalID, sessionID := event.Notification.GetOriginalMessageID(), event.Notification.GetPeerDataRequestSessionID()
	if originalID != "" || sessionID != "" {
		return true, originalID == peerID || sessionID == peerID, sender
	}
	// Older devices may omit correlation metadata. In that case a non-empty
	// conversation entry for the requested chat is the minimum usable evidence.
	for _, conversation := range event.Data.GetConversations() {
		rawJID := conversation.GetPnJID()
		if rawJID == "" {
			rawJID = conversation.GetID()
		}
		jid, err := types.ParseJID(rawJID)
		if err == nil && w.callSender(jid) == sender {
			return true, true, sender
		}
	}
	return true, false, sender
}
