package usecase

import (
	"context"
	"errors"
	"fmt"
	"testing"

	"apps/backend/internal/module/crm/domain"
	"apps/backend/internal/module/crm/repository"
)

func seedContact(t *testing.T, repo domain.Repository, ownerUID int64, handle, displayName, stage string) *domain.Contact {
	t.Helper()
	c, err := repo.UpsertContactByIdentity(context.Background(), &domain.Contact{
		OwnerUID: ownerUID, SourcePlatform: domain.PlatformThreads,
		AuthorHandle: handle, DisplayName: displayName, Stage: stage,
		OpportunityIDs: []string{"opp-" + handle}, LastTouchAt: domain.NowNano(),
	})
	if err != nil {
		t.Fatalf("seed contact %s: %v", handle, err)
	}
	return c
}

func TestContactListSearchPaginationAndCompleteCounts(t *testing.T) {
	repo := repository.NewMemory()
	svc := New(repo)
	ctx := context.Background()
	for i := 0; i < 25; i++ {
		stage := domain.StageNewFound
		if i%2 == 0 {
			stage = domain.StageEngaged
		}
		seedContact(t, repo, 42, fmt.Sprintf("buyer-%02d", i), fmt.Sprintf("客戶 %02d", i), stage)
	}

	list, total, counts, err := svc.ListContacts(ctx, 42, domain.ContactListFilter{Page: 2, PageSize: 20})
	if err != nil {
		t.Fatalf("list: %v", err)
	}
	if total != 25 || len(list) != 5 {
		t.Fatalf("pagination list=%d total=%d, want 5/25", len(list), total)
	}
	if counts[domain.StageEngaged] != 13 || counts[domain.StageNewFound] != 12 {
		t.Fatalf("stage counts = %+v", counts)
	}

	list, total, _, err = svc.ListContacts(ctx, 42, domain.ContactListFilter{Query: "客戶 07", Page: 1, PageSize: 20})
	if err != nil || total != 1 || len(list) != 1 || list[0].AuthorHandle != "buyer-07" {
		t.Fatalf("search list=%+v total=%d err=%v", list, total, err)
	}
}

func TestRemoveContactHidesItClosesFollowUpsAndCanBeReadded(t *testing.T) {
	repo := repository.NewMemory()
	svc := New(repo)
	ctx := context.Background()
	c := seedContact(t, repo, 42, "buyer", "買家", domain.StageEngaged)
	if _, err := svc.SetFollowUp(ctx, 42, c.ID, true, 3); err != nil {
		t.Fatalf("set follow-up: %v", err)
	}

	if err := svc.RemoveContact(ctx, 42, c.ID); err != nil {
		t.Fatalf("remove: %v", err)
	}
	if _, err := svc.GetContactOnly(ctx, 42, c.ID); !errors.Is(err, domain.ErrNotFound) {
		t.Fatalf("get removed err=%v, want ErrNotFound", err)
	}
	list, total, counts, err := svc.ListContacts(ctx, 42, domain.ContactListFilter{Page: 1, PageSize: 20})
	if err != nil || total != 0 || len(list) != 0 || counts[domain.StageEngaged] != 0 {
		t.Fatalf("removed contact still visible: list=%+v total=%d counts=%+v err=%v", list, total, counts, err)
	}
	followUps, totalFollowUps, err := repo.ListFollowUps(ctx, 42, domain.FollowUpListFilter{Status: domain.FollowUpDone, Page: 1, PageSize: 20})
	if err != nil || totalFollowUps != 1 || len(followUps) != 1 {
		t.Fatalf("active follow-up was not closed: list=%+v total=%d err=%v", followUps, totalFollowUps, err)
	}

	readded := seedContact(t, repo, 42, "buyer", "買家", domain.StageNewFound)
	if readded.ID != c.ID || readded.RemovedAt != 0 || readded.Stage != domain.StageNewFound {
		t.Fatalf("re-added contact = %+v, want same active identity", readded)
	}
}

func TestRemoveContactOwnerGuard(t *testing.T) {
	repo := repository.NewMemory()
	svc := New(repo)
	c := seedContact(t, repo, 42, "buyer", "買家", domain.StageNewFound)
	if err := svc.RemoveContact(context.Background(), 7, c.ID); !errors.Is(err, domain.ErrForbidden) {
		t.Fatalf("remove other owner err=%v, want ErrForbidden", err)
	}
}
