import requests
import string
import random


def randomString(len=10):
    """Generate a random string of fixed length"""
    letters = string.ascii_lowercase
    return "".join(random.choice(letters) for i in range(len))


# Defined once per test run
username = randomString()
projectName = randomString()

# The base URL of the API
base_url = "http://localhost:8080"

# Endpoint to test
registerPath = base_url + "/api/register"
loginPath = base_url + "/api/login"
addProjectPath = base_url + "/api/project"
submitReportPath = base_url + "/api/submitReport"
getWeeklyReportPath = base_url + "/api/getWeeklyReport"
getProjectPath = base_url + "/api/project"
signReportPath = base_url + "/api/signReport"
addUserToProjectPath = base_url + "/api/addUserToProject"
promoteToAdminPath = base_url + "/api/promoteToAdmin"
getUserProjectsPath = base_url + "/api/getUserProjects"


def test_get_user_projects():

    print("Testing get user projects")
    loginResponse = login("user2", "123")
    # Check if the user is added to the project
    response = requests.get(
        getUserProjectsPath,
        json={"username": "user2"},
        headers={"Authorization": "Bearer " + loginResponse.json()["token"]},
    )
    print(response.text)
    print(response.json())
    assert response.status_code == 200, "Get user projects failed"
    print("got user projects successfully")


# Posts the username and password to the register endpoint
def register(username: string, password: string):
    print("Registering with username: ", username, " and password: ", password)
    response = requests.post(
        registerPath, json={"username": username, "password": password}
    )
    print(response.text)
    return response


# Posts the username and password to the login endpoint
def login(username: string, password: string):
    print("Logging in with username: ", username, " and password: ", password)
    response = requests.post(
        loginPath, json={"username": username, "password": password}
    )
    print(response.text)
    return response


# Test function to login
def test_login():
    response = login(username, "always_same")
    assert response.status_code == 200, "Login failed"
    print("Login successful")
    return response.json()["token"]


# Test function to create a new user
def test_create_user():
    response = register(username, "always_same")
    assert response.status_code == 200, "Registration failed"
    print("Registration successful")


# Test function to add a project
def test_add_project():
    loginResponse = login(username, "always_same")
    token = loginResponse.json()["token"]
    response = requests.post(
        addProjectPath,
        json={"name": projectName, "description": "This is a project"},
        headers={"Authorization": "Bearer " + token},
    )
    print(response.text)
    assert response.status_code == 200, "Add project failed"
    print("Add project successful")


# Test function to submit a report
def test_submit_report():
    token = login(username, "always_same").json()["token"]
    response = requests.post(
        submitReportPath,
        json={
            "projectName": projectName,
            "week": 1,
            "developmentTime": 10,
            "meetingTime": 5,
            "adminTime": 5,
            "ownWorkTime": 10,
            "studyTime": 10,
            "testingTime": 10,
        },
        headers={"Authorization": "Bearer " + token},
    )
    print(response.text)
    assert response.status_code == 200, "Submit report failed"
    print("Submit report successful")


# Test function to get a weekly report
def test_get_weekly_report():
    token = login(username, "always_same").json()["token"]
    response = requests.get(
        getWeeklyReportPath,
        headers={"Authorization": "Bearer " + token},
        params={"username": username, "projectName": projectName, "week": 1},
    )
    print(response.text)
    assert response.status_code == 200, "Get weekly report failed"


# Tests getting a project by id
def test_get_project():
    token = login(username, "always_same").json()["token"]
    response = requests.get(
        getProjectPath + "/1",  # Assumes that the project with id 1 exists
        headers={"Authorization": "Bearer " + token},
    )
    print(response.text)
    assert response.status_code == 200, "Get project failed"


# Test function to add a user to a project
def test_add_user_to_project():
    # Log in as a site admin
    admin_username = randomString()
    admin_password = "admin_password"
    print(
        "Registering with username: ", admin_username, " and password: ", admin_password
    )
    response = requests.post(
        registerPath, json={"username": admin_username, "password": admin_password}
    )
    print(response.text)

    admin_token = login(admin_username, admin_password).json()["token"]
    response = requests.post(
        promoteToAdminPath,
        json={"username": admin_username},
        headers={"Authorization": "Bearer " + admin_token},
    )
    print(response.text)
    assert response.status_code == 200, "Promote to site admin failed"
    print("Admin promoted to site admin successfully")

    # Create a new user to add to the project
    new_user = randomString()
    register(new_user, "new_user_password")

    # Add the new user to the project as a member
    response = requests.put(
        addUserToProjectPath,
        json={"projectName": projectName, "username": new_user, "role": "member"},
        headers={"Authorization": "Bearer " + admin_token},
    )

    print(response.text)
    assert response.status_code == 200, "Add user to project failed"
    print("Add user to project successful")


# Test function to sign a report
def test_sign_report():
    # Create a project manager user
    project_manager = randomString()
    register(project_manager, "project_manager_password")

    # Register an admin
    admin_username = randomString()
    admin_password = "admin_password2"
    print(
        "Registering with username: ", admin_username, " and password: ", admin_password
    )
    response = requests.post(
        registerPath, json={"username": admin_username, "password": admin_password}
    )
    print(response.text)

    # Log in as the admin
    admin_token = login(admin_username, admin_password).json()["token"]
    response = requests.post(
        promoteToAdminPath,
        json={"username": admin_username},
        headers={"Authorization": "Bearer " + admin_token},
    )

    response = requests.put(
        addUserToProjectPath,
        json={
            "projectName": projectName,
            "username": project_manager,
            "role": "project_manager",
        },
        headers={"Authorization": "Bearer " + admin_token},
    )
    assert response.status_code == 200, "Add project manager to project failed"
    print("Project manager added to project successfully")

    # Log in as the project manager
    project_manager_token = login(project_manager, "project_manager_password").json()[
        "token"
    ]

    # Submit a report for the project
    token = login(username, "always_same").json()["token"]
    response = requests.post(
        submitReportPath,
        json={
            "projectName": projectName,
            "week": 1,
            "developmentTime": 10,
            "meetingTime": 5,
            "adminTime": 5,
            "ownWorkTime": 10,
            "studyTime": 10,
            "testingTime": 10,
        },
        headers={"Authorization": "Bearer " + token},
    )
    assert response.status_code == 200, "Submit report failed"
    print("Submit report successful")

    # Retrieve the report ID
    response = requests.get(
        getWeeklyReportPath,
        headers={"Authorization": "Bearer " + token},
        params={"username": username, "projectName": projectName, "week": 1},
    )
    print(response.text)
    report_id = response.json()["reportId"]

    # Sign the report as the project manager
    response = requests.post(
        signReportPath,
        json={"reportId": report_id},
        headers={"Authorization": "Bearer " + project_manager_token},
    )
    assert response.status_code == 200, "Sign report failed"
    print("Sign  report successful")

    # Retrieve the report ID again for confirmation
    response = requests.get(
        getWeeklyReportPath,
        headers={"Authorization": "Bearer " + token},
        params={"username": username, "projectName": projectName, "week": 1},
    )
    print(response.text)


if __name__ == "__main__":
    test_get_user_projects()
    test_create_user()
    test_login()
    test_add_project()
    test_submit_report()
    test_get_weekly_report()
    test_get_project()
    test_sign_report()
    test_add_user_to_project()