package database

import (
	"testing"
)

// Tests are not guaranteed to be sequential

func setupState() (Database, error) {
	db := DbConnect(":memory:")
	err := db.Migrate("../../migrations")
	if err != nil {
		return nil, err
	}
	return db, nil
}

func TestDbConnect(t *testing.T) {
	db := DbConnect(":memory:")
	_ = db
}

func TestDbAddUser(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}
	err = db.AddUser("test", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}
}

func TestDbGetUserId(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}
	if db.AddUser("test", "password") != nil {
		t.Error("AddUser failed")
	}

	var id int

	id, err = db.GetUserId("test")
	if err != nil {
		t.Error("GetUserId failed:", err)
	}
	if id != 1 {
		t.Error("GetUserId failed: expected 1, got", id)
	}
}

func TestDbAddProject(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddProject("test", "description", "test")
	if err != nil {
		t.Error("AddProject failed:", err)
	}
}

func TestDbRemoveUser(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.RemoveUser("test")
	if err != nil {
		t.Error("RemoveUser failed:", err)
	}
}

func TestPromoteToAdmin(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("test", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.PromoteToAdmin("test")
	if err != nil {
		t.Error("PromoteToAdmin failed:", err)
	}
}

func TestAddWeeklyReport(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("testuser", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddProject("testproject", "description", "testuser")
	if err != nil {
		t.Error("AddProject failed:", err)
	}

	err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1)
	if err != nil {
		t.Error("AddWeeklyReport failed:", err)
	}
}

func TestAddUserToProject(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("testuser", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddProject("testproject", "description", "testuser")
	if err != nil {
		t.Error("AddProject failed:", err)
	}

	err = db.AddWeeklyReport("testproject", "testuser", 1, 1, 1, 1, 1, 1, 1)
	if err != nil {
		t.Error("AddWeeklyReport failed:", err)
	}

	err = db.AddUserToProject("testuser", "testproject", "user")
	if err != nil {
		t.Error("AddUserToProject failed:", err)
	}
}

func TestChangeUserRole(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("testuser", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddProject("testproject", "description", "testuser")
	if err != nil {
		t.Error("AddProject failed:", err)
	}

	err = db.AddUserToProject("testuser", "testproject", "user")
	if err != nil {
		t.Error("AddUserToProject failed:", err)
	}

	role, err := db.GetUserRole("testuser", "testproject")
	if err != nil {
		t.Error("GetUserRole failed:", err)
	}
	if role != "user" {
		t.Error("GetUserRole failed: expected user, got", role)
	}

	err = db.ChangeUserRole("testuser", "testproject", "admin")
	if err != nil {
		t.Error("ChangeUserRole failed:", err)
	}

	role, err = db.GetUserRole("testuser", "testproject")
	if err != nil {
		t.Error("GetUserRole failed:", err)
	}
	if role != "admin" {
		t.Error("GetUserRole failed: expected admin, got", role)
	}

}

func TestGetAllUsersProject(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("testuser1", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddUser("testuser2", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddProject("testproject", "description", "testuser1")
	if err != nil {
		t.Error("AddProject failed:", err)
	}

	err = db.AddUserToProject("testuser1", "testproject", "project_manager")
	if err != nil {
		t.Error("AddUserToProject failed:", err)
	}

	err = db.AddUserToProject("testuser2", "testproject", "user")
	if err != nil {
		t.Error("AddUserToProject failed:", err)
	}

	users, err := db.GetAllUsersProject("testproject")
	if err != nil {
		t.Error("GetAllUsersProject failed:", err)
	}

	// Check if both users are returned with their roles
	if len(users) != 2 {
		t.Errorf("Expected 2 users, got %d", len(users))
	}

	// Check if testuser1 has project manager role
	foundProjectManager := false
	for _, user := range users {
		if user.Username == "testuser1" && user.UserRole == "project_manager" {
			foundProjectManager = true
			break
		}
	}
	if !foundProjectManager {
		t.Error("Project Manager user not found")
	}

	// Check if testuser2 has user role
	foundUser := false
	for _, user := range users {
		if user.Username == "testuser2" && user.UserRole == "user" {
			foundUser = true
			break
		}
	}
	if !foundUser {
		t.Error("User user not found")
	}
}

func TestGetAllUsersApplication(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("testuser1", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddUser("testuser2", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	users, err := db.GetAllUsersApplication()
	if err != nil {
		t.Error("GetAllUsersApplication failed:", err)
	}

	// Check if both users are returned
	if len(users) != 2 {
		t.Errorf("Expected 2 users, got %d", len(users))
	}

	// Check if the test users are included in the list
	foundTestUser1 := false
	foundTestUser2 := false
	for _, user := range users {
		if user == "testuser1" {
			foundTestUser1 = true
		}
		if user == "testuser2" {
			foundTestUser2 = true
		}
	}

	if !foundTestUser1 {
		t.Error("testuser1 not found")
	}
	if !foundTestUser2 {
		t.Error("testuser2 not found")
	}
}

func TestGetProjectsForUser(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("testuser", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddProject("testproject", "description", "testuser")
	if err != nil {
		t.Error("AddProject failed:", err)
	}

	err = db.AddUserToProject("testuser", "testproject", "user")
	if err != nil {
		t.Error("AddUserToProject failed:", err)
	}

	projects1, err := db.GetAllProjects()
	if err != nil {
		t.Error("GetAllProjects failed:", err)
	}

	if len(projects1) != 1 {
		t.Error("GetAllProjects failed: expected 1, got", len(projects1))
	}

	projects, err := db.GetProjectsForUser("testuser")
	if err != nil {
		t.Error("GetProjectsForUser failed:", err)
	}

	if len(projects) != 1 {
		t.Error("GetProjectsForUser failed: expected 1, got", len(projects))
	}
}

func TestAddProject(t *testing.T) {
	db, err := setupState()
	if err != nil {
		t.Error("setupState failed:", err)
	}

	err = db.AddUser("testuser", "password")
	if err != nil {
		t.Error("AddUser failed:", err)
	}

	err = db.AddProject("testproject", "description", "testuser")
	if err != nil {
		t.Error("AddProject failed:", err)
	}

	// Retrieve the added project to verify its existence
	projects, err := db.GetAllProjects()
	if err != nil {
		t.Error("GetAllProjects failed:", err)
	}

	// Check if the project was added successfully
	found := false
	for _, project := range projects {
		if project.Name == "testproject" {
			found = true
			break
		}
	}
	if !found {
		t.Error("Added project not found")
	}
}