package services

import (
	"context"
	"go.mau.fi/whatsmeow"
	"go.mau.fi/whatsmeow/proto/waCommon"
	"go.mau.fi/whatsmeow/proto/waE2E"
	"go.mau.fi/whatsmeow/proto/waWeb"
	"go.mau.fi/whatsmeow/store"
	"go.mau.fi/whatsmeow/types"
	"go.mau.fi/whatsmeow/types/events"
	"google.golang.org/protobuf/proto"
	"testing"
	"time"
)

type groupProfileStore struct {
	store.ContactStore
	rows map[types.JID]types.ContactInfo
}

func (s groupProfileStore) GetContact(_ context.Context, jid types.JID) (types.ContactInfo, error) {
	return s.rows[jid], nil
}

func TestCachedGroupParticipantNamesUseOnlyThisAccountAndDoNotGuessLID(t *testing.T) {
	jid := types.NewJID("628111111111", types.DefaultUserServer)
	withProfile := &waInstance{client: &whatsmeow.Client{Store: &store.Device{Contacts: groupProfileStore{rows: map[types.JID]types.ContactInfo{jid: {PushName: "Budi", FullName: "Nama buku alamat"}}}}}}
	withoutProfile := &waInstance{}
	names := withProfile.CachedParticipantNames(context.Background(), []string{jid.String(), jid.String(), "123456@lid"})
	if names[jid.String()] != "Budi" || names["123456@lid"] != "" || len(names) != 2 {
		t.Fatal("incorrect local profile resolution", names)
	}
	names = withoutProfile.CachedParticipantNames(context.Background(), []string{jid.String(), "123456@lid"})
	if names[jid.String()] != "+628111111111" || names["123456@lid"] != "" {
		t.Fatal("profile leaked across accounts or LID became phone", names)
	}
}

func TestGroupPinActorComesFromActionNotPinnedMessageAuthor(t *testing.T) {
	old := onMessagePin
	t.Cleanup(func() { onMessagePin = old })
	var got MessagePinUpdate
	onMessagePin = func(_ uint, update MessagePinUpdate) error { got = update; return nil }
	group := types.NewJID("120363000000001", types.GroupServer)
	actor := types.NewJID("628111111111", types.DefaultUserServer)
	w := &waInstance{agentID: 1, client: &whatsmeow.Client{}}
	event := &events.Message{Info: types.MessageInfo{ID: "action", PushName: "Budi", Timestamp: time.Now(), MessageSource: types.MessageSource{Chat: group, Sender: actor, IsGroup: true}}, Message: &waE2E.Message{PinInChatMessage: &waE2E.PinInChatMessage{Key: &waCommon.MessageKey{ID: proto.String("target"), FromMe: proto.Bool(true), Participant: proto.String("628999999999@s.whatsapp.net")}, Type: waE2E.PinInChatMessage_PIN_FOR_ALL.Enum()}}}
	w.handleMessagePin(event)
	if got.ActorName != "Budi" || got.ActorJID != actor.String() || got.ActorFromMe {
		t.Fatalf("wrong actor: %+v", got)
	}
	event.Info.IsFromMe = true
	event.Message.PinInChatMessage.Key.FromMe = proto.Bool(false)
	w.handleMessagePin(event)
	if !got.ActorFromMe {
		t.Fatal("own action confused with target direction")
	}
}

func TestHistoryPinActorUsesAddonKeyAndKeepsBareStubAsActivityOnly(t *testing.T) {
	group := "120363000000001@g.us"
	now := time.Now().Truncate(time.Second)
	web := &waWeb.WebMessageInfo{Key: &waCommon.MessageKey{ID: proto.String("target"), RemoteJID: &group, FromMe: proto.Bool(true)}, PushName: proto.String("Original author"), MessageTimestamp: proto.Uint64(uint64(now.Add(-time.Hour).Unix())), MessageAddOns: []*waWeb.MessageAddOn{{MessageAddOnKey: &waCommon.MessageKey{ID: proto.String("addon-action"), Participant: proto.String("628111111111@s.whatsapp.net"), FromMe: proto.Bool(false)}, ServerTimestampMS: proto.Int64(now.UnixMilli()), MessageAddOn: &waE2E.Message{PinInChatMessage: &waE2E.PinInChatMessage{Key: &waCommon.MessageKey{ID: proto.String("target")}, Type: waE2E.PinInChatMessage_PIN_FOR_ALL.Enum()}}}}}
	pins := historyMessagePins(web, group)
	if len(pins) != 1 || pins[0].EventMessageID != "addon-action" || pins[0].ActorJID != "628111111111@s.whatsapp.net" || pins[0].ActorFromMe || pins[0].ActorName != "" {
		t.Fatalf("addon inherited original author: %+v", pins)
	}
	stub := &waWeb.WebMessageInfo{Key: &waCommon.MessageKey{ID: proto.String("stub-action"), RemoteJID: &group, FromMe: proto.Bool(true)}, MessageTimestamp: proto.Uint64(uint64(now.Unix())), MessageStubType: waWeb.WebMessageInfo_PINNED_MESSAGE_IN_CHAT.Enum()}
	pins = historyMessagePins(stub, group)
	if len(pins) != 1 || !pins[0].ActionOnly || !pins[0].ActorFromMe || pins[0].MessageID != "" || pins[0].ExpiresAt != nil {
		t.Fatalf("stub guessed target/expiry or lost own actor: %+v", pins)
	}
}
