from typing import Callable, List, Optional, Union

from tqdm import tqdm

from supervisely import get_project_class
from supervisely.api.api import Api
from supervisely.project import read_project


def upload(
    src_dir: str,
    api: Api,
    workspace_id: int,
    project_name: Optional[str] = None,
    log_progress: bool = True,
    progress_cb: Optional[Union[tqdm, Callable]] = None,
    **kwargs,
) -> None:
    """
    Uploads project of any modality from the local directory. See methods `sly.upload_project`,
    `sly.upload_video_project`, `sly.upload_volume_project`, `sly.upload_pointcloud_project`,
    `sly.upload_pointcloud_episode_project` to examine full list of possible arguments.

    :param src_dir: Source path to local directory.
    :type src_dir: str
    :param api: Supervisely API address and token.
    :type api: :class:`~supervisely.api.api.Api`
    :param workspace_id: Destination workspace ID.
    :type workspace_id: int
    :param project_name: Custom project name. By default, it's a directory name.
    :type project_name: str, optional
    :param log_progress: Show uploading logs in the output.
    :type log_progress: bool
    :param progress_cb: Function for tracking upload progress.
    :type progress_cb: tqdm or callable, optional

    :returns: None.
    :rtype: NoneType

    :Usage Example:

        .. code-block:: python

            import os
            from tqdm import tqdm
            from dotenv import load_dotenv

            import supervisely as sly

            # Load secrets and create API object from .env file (recommended)
            # Learn more here: https://developer.supervisely.com/getting-started/basics-of-authentication
            if sly.is_development():
                load_dotenv(os.path.expanduser("~/supervisely.env"))

            api = sly.Api.from_env()

            src_dir = '/your/local/source/dir'

            # Upload image project
            project_fs = sly.read_project(src_dir)

            pbar = tqdm(desc="Uploading image project", total=project_fs.total_items)
            sly.upload(src_dir, api, workspace_id, project_name, progress_cb=pbar)

            # Upload video project
            sly.upload(
                src_dir,
                api,
                workspace_id,
                project_name="Some Video Project",
                log_progress=True,
                include_custom_data=True
            )

            # Upload volume project
            sly.upload(src_dir, api, workspace_id, project_name="Some Volume Project", log_progress=True)

            # Upload pointcloud project
            project_fs = read_project(directory)

            pbar = tqdm(desc="Uploading pointcloud project", total=project_fs.total_items)
            sly.upload(
                src_dir,
                api,
                workspace_id,
                project_name="Some Pointcloud Project",
                progress_cb=pbar,
            )

            # Upload pointcloud episodes project
            project_fs = read_project(src_dir)

            with tqdm(desc="Upload pointcloud episodes project", total=project_fs.total_items) as pbar:
                sly.upload(
                    src_dir,
                    api,
                    workspace_id,
                    project_name="Some Pointcloud Episodes Project",
                    progress_cb=pbar,
                )
    """

    project_fs = read_project(src_dir)

    if progress_cb is not None:
        log_progress = False

    project_class = get_project_class(project_fs.meta.project_type)
    project_class.upload(
        src_dir,
        api=api,
        workspace_id=workspace_id,
        project_name=project_name,
        log_progress=log_progress,
        progress_cb=progress_cb,
        **kwargs,
    )
