package player

import (
	"database/sql"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/gin-gonic/gin"
)

func TestGetPlayers(t *testing.T) {
	// Set Gin to Test Mode
	gin.SetMode(gin.TestMode)

	t.Run("successful retrieval", func(t *testing.T) {
		// Create a new HTTP recorder and context
		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)

		// Create a mock database connection
		db, mock, err := sqlmock.New()
		if err != nil {
			t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
		}
		defer db.Close()

		// Define the expected rows and columns
		rows := sqlmock.NewRows([]string{"uuid", "email", "username", "firstname", "lastname", "birthday", "is_active", "created_at", "role"}).
			AddRow("uuid-1", "player1@example.com", "player1", "first1", "last1", nil, true, nil, "{player}")

		// Expect a query to be made
		mock.ExpectQuery(getPLayerWithRolesQuery).WillReturnRows(rows)

		// Call the handler
		GetPlayers(c, db)

		// Check the status code and response body
		if w.Code != http.StatusOK {
			t.Errorf("expected status code %d but got %d", http.StatusOK, w.Code)
		}

		// TODO: Add assertion for the response body

		// Ensure all expectations were met
		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("there were unfulfilled expectations: %s", err)
		}
	})

	t.Run("database error", func(t *testing.T) {
		// Create a new HTTP recorder and context
		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)

		// Create a mock database connection
		db, mock, err := sqlmock.New()
		if err != nil {
			t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
		}
		defer db.Close()

		// Expect a query to fail
		mock.ExpectQuery(getPLayerWithRolesQuery).WillReturnError(sql.ErrConnDone)

		// Call the handler
		GetPlayers(c, db)

		// Check the status code and response body
		if w.Code != http.StatusInternalServerError {
			t.Errorf("expected status code %d but got %d", http.StatusInternalServerError, w.Code)
		}

		// Ensure all expectations were met
		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("there were unfulfilled expectations: %s", err)
		}
	})
}

func TestGetPlayer(t *testing.T) {
	gin.SetMode(gin.TestMode)

	t.Run("successful retrieval", func(t *testing.T) {
		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)
		c.Params = gin.Params{gin.Param{Key: "id", Value: "uuid-1"}}

		db, mock, err := sqlmock.New()
		if err != nil {
			t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
		}
		defer db.Close()

		rows := sqlmock.NewRows([]string{"uuid", "username", "email"}).
			AddRow("uuid-1", "player1", "player1@example.com")

		mock.ExpectQuery("SELECT id, name, email FROM users WHERE id = \\$1").WithArgs("uuid-1").WillReturnRows(rows)
		mock.ExpectQuery("SELECT role FROM roles WHERE player_id = \\$1").WithArgs("uuid-1").WillReturnRows(sqlmock.NewRows([]string{"role"}).AddRow("player"))

		GetPlayer(c, db, "uuid-1")

		if w.Code != http.StatusOK {
			t.Errorf("expected status code %d but got %d", http.StatusOK, w.Code)
		}

		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("there were unfulfilled expectations: %s", err)
		}
	})

	t.Run("not found", func(t *testing.T) {
		w := httptest.NewRecorder()
		c, _ := gin.CreateTestContext(w)
		c.Params = gin.Params{gin.Param{Key: "id", Value: "uuid-not-found"}}

		db, mock, err := sqlmock.New()
		if err != nil {
			t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
		}
		defer db.Close()

		mock.ExpectQuery("SELECT id, name, email FROM users WHERE id = \\$1").WithArgs("uuid-not-found").WillReturnError(sql.ErrNoRows)

		GetPlayer(c, db, "uuid-not-found")

		if w.Code != http.StatusInternalServerError {
			t.Errorf("expected status code %d but got %d", http.StatusInternalServerError, w.Code)
		}

		if err := mock.ExpectationsWereMet(); err != nil {
			t.Errorf("there were unfulfilled expectations: %s", err)
		}
	})
}
