package graphql_test

import (
	"context"
	"os"
	"tercul/internal/adapters/graphql"
	"tercul/internal/app"
	"tercul/internal/app/auth"
	"tercul/internal/domain"
	platform_auth "tercul/internal/platform/auth"
	"tercul/internal/testutil"
	"testing"

	"github.com/stretchr/testify/suite"
)

type AuthMutationTestSuite struct {
	testutil.IntegrationTestSuite
	App      *app.Application
	resolver graphql.MutationResolver
}

func TestAuthMutations(t *testing.T) {
	suite.Run(t, new(AuthMutationTestSuite))
}

func (s *AuthMutationTestSuite) SetupSuite() {
	s.IntegrationTestSuite.SetupSuite(&testutil.TestConfig{
		DBPath: "auth_mutations_test.db",
	})
	s.App = s.IntegrationTestSuite.App
}

func (s *AuthMutationTestSuite) TearDownSuite() {
	s.IntegrationTestSuite.TearDownSuite()
	_ = os.Remove("auth_mutations_test.db")
}

func (s *AuthMutationTestSuite) SetupTest() {
	s.IntegrationTestSuite.SetupTest()
	s.resolver = (&graphql.Resolver{App: s.App}).Mutation()
}

func (s *AuthMutationTestSuite) TestChangePassword() {
	// Helper to create a user for tests
	createUser := func(username, email, password string) *domain.User {
		resp, err := s.App.Auth.Commands.Register(context.Background(), auth.RegisterInput{
			Username: username,
			Email:    email,
			Password: password,
		})
		s.Require().NoError(err)
		return resp.User
	}

	// Helper to create a context with JWT claims
	contextWithClaims := func(user *domain.User) context.Context {
		return testutil.ContextWithClaims(context.Background(), &platform_auth.Claims{
			UserID: user.ID,
			Role:   string(user.Role),
		})
	}

	s.Run("Success", func() {
		// Arrange
		initialPassword := "password123"
		newPassword := "newPassword456"
		user := createUser("testuser-changepw", "testuser.changepw@test.com", initialPassword)
		ctx := contextWithClaims(user)

		// Act
		success, err := s.resolver.ChangePassword(ctx, initialPassword, newPassword)

		// Assert
		s.Require().NoError(err)
		s.True(success)

		// Verify the password change by trying to log in with the new and old passwords
		_, err = s.App.Auth.Commands.Login(context.Background(), auth.LoginInput{Email: user.Email, Password: newPassword})
		s.NoError(err, "Login with new password should succeed")

		_, err = s.App.Auth.Commands.Login(context.Background(), auth.LoginInput{Email: user.Email, Password: initialPassword})
		s.Error(err, "Login with old password should fail")
		s.ErrorIs(err, auth.ErrInvalidCredentials)
	})

	s.Run("Incorrect current password", func() {
		// Arrange
		initialPassword := "password123"
		newPassword := "newPassword456"
		user := createUser("testuser-wrongpw", "testuser.wrongpw@test.com", initialPassword)
		ctx := contextWithClaims(user)

		// Act
		success, err := s.resolver.ChangePassword(ctx, "wrong-password", newPassword)

		// Assert
		s.Require().Error(err)
		s.False(success)
		s.ErrorIs(err, auth.ErrInvalidCredentials)

		// Verify the password was not changed
		_, loginErr := s.App.Auth.Commands.Login(context.Background(), auth.LoginInput{Email: user.Email, Password: initialPassword})
		s.NoError(loginErr, "Login with original password should still succeed")
	})

	s.Run("Unauthenticated user", func() {
		// Act
		success, err := s.resolver.ChangePassword(context.Background(), "any-password", "any-new-password")

		// Assert
		s.Require().Error(err)
		s.False(success)
		s.ErrorIs(err, domain.ErrUnauthorized)
	})
}
