package network_test

import (
	"context"
	"os"
	"testing"

	"github.com/flowy-live/llink/internal/network"
	"github.com/flowy-live/llink/internal/testhelper"
	"github.com/jackc/pgx/v5/pgxpool"
	"github.com/stretchr/testify/assert"
)

var dbPool *pgxpool.Pool

func TestMain(m *testing.M) {
	dbPool = testhelper.SetupTestDB()
	defer testhelper.TeardownTestDB()

	ret := m.Run()
	os.Exit(ret)
}

func TestNetworkService(t *testing.T) {
	ctx := context.Background()
	svc := network.NewService(dbPool)

	// Test Create
	createdNetwork, err := svc.Create(ctx, "Test Network", "admin@example.com")
	assert.NoError(t, err)
	assert.NotEmpty(t, createdNetwork.ID)
	assert.Equal(t, "Test Network", createdNetwork.Name)
	assert.Equal(t, "admin@example.com", createdNetwork.AdminEmail)
	assert.NotZero(t, createdNetwork.CreatedAt)

	// Test GetByID
	foundNetwork, err := svc.GetByID(ctx, createdNetwork.ID)
	assert.NoError(t, err)
	assert.Equal(t, createdNetwork.ID, foundNetwork.ID)
	assert.Equal(t, createdNetwork.Name, foundNetwork.Name)
	assert.Equal(t, createdNetwork.AdminEmail, foundNetwork.AdminEmail)

	// Test GetByID with non-existent id
	_, err = svc.GetByID(ctx, "network_nonexistent")
	assert.Error(t, err)
	assert.ErrorIs(t, err, network.ErrNotFound)

	// Test SetName
	err = svc.SetName(ctx, createdNetwork.ID, "Updated Network Name")
	assert.NoError(t, err)

	// Verify name was updated
	updatedNetwork, err := svc.GetByID(ctx, createdNetwork.ID)
	assert.NoError(t, err)
	assert.Equal(t, "Updated Network Name", updatedNetwork.Name)

	// Test SetName with non-existent id
	err = svc.SetName(ctx, "network_nonexistent", "New Name")
	assert.Error(t, err)
	assert.ErrorIs(t, err, network.ErrNotFound)

	// Test AddMembers
	err = svc.AddMembers(ctx, createdNetwork.ID, []string{"member1@example.com", "member2@example.com"})
	assert.NoError(t, err)

	// Test ListForEmail - should find network for admin
	networks, err := svc.ListForEmail(ctx, "admin@example.com")
	assert.NoError(t, err)
	assert.Len(t, networks, 1)
	assert.Equal(t, createdNetwork.ID, networks[0].ID)

	// Test ListForEmail - should find network for member
	networks, err = svc.ListForEmail(ctx, "member1@example.com")
	assert.NoError(t, err)
	assert.Len(t, networks, 1)
	assert.Equal(t, createdNetwork.ID, networks[0].ID)

	// Test ListForEmail - should return empty for non-member
	networks, err = svc.ListForEmail(ctx, "stranger@example.com")
	assert.NoError(t, err)
	assert.Len(t, networks, 0)

	// Test RemoveMember
	err = svc.RemoveMember(ctx, createdNetwork.ID, "member1@example.com")
	assert.NoError(t, err)

	// Verify member was removed
	networks, err = svc.ListForEmail(ctx, "member1@example.com")
	assert.NoError(t, err)
	assert.Len(t, networks, 0)

	// member2 should still have access
	networks, err = svc.ListForEmail(ctx, "member2@example.com")
	assert.NoError(t, err)
	assert.Len(t, networks, 1)

	// Create another network and verify ListForEmail returns multiple
	network2, err := svc.Create(ctx, "Second Network", "member2@example.com")
	assert.NoError(t, err)

	networks, err = svc.ListForEmail(ctx, "member2@example.com")
	assert.NoError(t, err)
	assert.Len(t, networks, 2)

	// Verify both networks are returned
	networkIDs := []string{networks[0].ID, networks[1].ID}
	assert.Contains(t, networkIDs, createdNetwork.ID)
	assert.Contains(t, networkIDs, network2.ID)
}
