from contextlib import contextmanager
from packaging.version import Version
from posit import connect
from posit.connect.content import ContentItem
from posit.connect.errors import ClientError
from posit.connect.users import User


def out_of_date(version: str) -> bool:
    """Check if Quarto version is out of date.

    Parameters
    ----------
    version : str
        A Quarto version identifier.

    Returns
    -------
    bool
        True if the Quarto version is out of date.
    """
    return (
        Version("1.4.000") < Version(version) < Version("1.4.557") or
        Version("1.5.000") < Version(version) < Version("1.5.52")
    )


@contextmanager
def temporary_permissions(current_user: User, item: ContentItem):
    """Use a temporary permission.

    Creates a temporary permission if the current_user does not have 'owner' permissions. After yielding, any permissions that were created are removed.

    Parameters
    ----------
    current_user : User
        The user executing this script.
    item : ContentItem
        The content to update
    """
    if current_user.guid != item.owner_guid:
        try:
            print("Creating temporary permission...")
            temporary_permission = item.permissions.create(
                principal_guid=current_user.guid, principal_type="user", role="owner"
            )
        except ClientError as e:
            if e.error_code == 154:
                print("Permission already exists...")
                temporary_permission = None
            else:
                raise e
    else:
        temporary_permission = None

    try:
        yield
    finally:
        if temporary_permission:
            print("Removing temporary permission...")
            temporary_permission.delete()


def main():
    """Refresh Quarto content to latest version.

    Checks for content with a Quarto Version between 1.4.000 and 1.4.557 or
    1.5.000 and 1.5.52 and then refreshes it. This action
    renders the content using the latest major Quarto version installed on the
    Connect server.
    """
    client = connect.Client()
    current_user = client.me

    content = client.content.find()
    outdated_content = [
        item
        for item in content
        if item.quarto_version and out_of_date(item.quarto_version)
    ]

    print(f"Found {len(outdated_content)} items to update...")

    for item in outdated_content:
        print(f"Content {item.dashboard_url} set to Quarto {item.quarto_version}...")
        with temporary_permissions(current_user, item):
            print(f"Refreshing '{item.dashboard_url}'")
            task = item.deploy()
            task.wait_for()
            if task.error_code != 0:
                print(f"Failed to refresh '{item.dashboard_url}'")
                print(task.error_message)
            else:
                print(f"Successfully refreshed '{item.dashboard_url}'")


if __name__ == "__main__":
    main()
