from ..io.path import clean_path as clean_path
from ..print.message import info as info, progress as progress, warning as warning
from .cd_utils import clean_version as clean_version, format_changelog as format_changelog, handle_response as handle_response, version_to_float as version_to_float
from collections.abc import Callable as Callable
from dataclasses import dataclass
from typing import Any

@dataclass
class PlatformConfig:
    """ Configuration for a Git hosting platform release. """
    base_url: str
    project_identifier: str
    headers: dict[str, str]
    version: str
    build_folder: str
    endswith: list[str]
    project_api_url: str
    web_url: str
    tag_api_path: str = ...
    commit_api_path: str = ...
    release_api_path: str = ...
    commit_url_path: str = ...
    compare_url_path: str = ...
    platform_name: str = ...

def validate_required_keys(config: dict[str, Any], required_keys: list[str], config_name: str) -> None:
    """ Validate that required keys exist in a configuration dictionary.

\tArgs:
\t\tconfig:        Configuration dictionary to validate
\t\trequired_keys: List of required key names
\t\tconfig_name:   Name of the configuration (for error messages)
\tRaises:
\t\tValueError: If any required key is missing
\t"""
def check_existing_tag(config: PlatformConfig, tag_url: str) -> bool:
    """ Check if a tag exists.

\tArgs:
\t\tconfig:  Platform configuration
\t\ttag_url: URL to check for tag existence
\tReturns:
\t\tbool: True if tag exists
\t"""
def prompt_delete_existing(config: PlatformConfig, delete_release_func: Callable[[PlatformConfig], None], delete_tag_func: Callable[[PlatformConfig], None]) -> bool:
    """ Prompt user to delete existing tag and release.

\tArgs:
\t\tconfig:              Platform configuration
\t\tdelete_release_func: Function to delete the release
\t\tdelete_tag_func:     Function to delete the tag
\tReturns:
\t\tbool: True if user chose to delete, False otherwise
\t"""
def handle_existing_tag(config: PlatformConfig, tag_url: str, delete_tag_func: Callable[[PlatformConfig], None], delete_release_func: Callable[[PlatformConfig], None]) -> bool:
    """ Check if tag exists and handle deletion if needed.

\tArgs:
\t\tconfig:              Platform configuration
\t\ttag_url:             URL to check if tag exists
\t\tdelete_tag_func:     Function to delete the tag
\t\tdelete_release_func: Function to delete the release
\tReturns:
\t\tbool: True if we can proceed with creating the release
\t"""
def get_latest_tag(config: PlatformConfig, sha_extractor: Callable[[dict[str, Any]], str]) -> tuple[str, str] | tuple[None, None]:
    """ Get latest tag information.

\tArgs:
\t\tconfig:        Platform configuration
\t\tsha_extractor: Function to extract SHA from a tag dict
\tReturns:
\t\ttuple: (sha, version) or (None, None)
\t"""
def paginate_api(url: str, headers: dict[str, str], params: dict[str, str], per_page: int = 100) -> list[dict[str, Any]]:
    """ Paginate through all results from an API endpoint.

\tArgs:
\t\turl:      API URL
\t\theaders:  HTTP headers
\t\tparams:   Query parameters
\t\tper_page: Number of items per page
\tReturns:
\t\tlist: All results from all pages
\t"""
def get_commits_since_tag(config: PlatformConfig, latest_tag_sha: str | None, date_extractor: Callable[[dict[str, Any]], str]) -> list[dict[str, Any]]:
    """ Get commits since last tag.

\tArgs:
\t\tconfig:         Platform configuration
\t\tlatest_tag_sha: SHA of the latest tag commit (or None)
\t\tdate_extractor: Function to extract date from a commit dict
\tReturns:
\t\tlist: List of commits since the tag
\t"""
def generate_changelog(commits: list[tuple[str, str]], config: PlatformConfig, latest_tag_version: str | None) -> str:
    """ Generate changelog from commits using platform-specific URL patterns.

\tArgs:
\t\tcommits:            List of (sha, message) tuples
\t\tconfig:             Platform configuration
\t\tlatest_tag_version: Previous version for comparison link
\tReturns:
\t\tstr: Generated changelog text
\t"""
def upload_files(config: PlatformConfig, upload_func: Callable[[str, str], None]) -> None:
    """ Upload files matching the specified suffixes.

\tArgs:
\t\tconfig:      Platform configuration
\t\tupload_func: Function to upload a single file (takes file path and file name)
\t"""
def log_success(config: PlatformConfig) -> None:
    """ Log a success message after upload.

\tArgs:
\t\tconfig: Platform configuration
\t"""
def delete_resource(config: PlatformConfig, url: str, resource_name: str) -> None:
    ''' Delete a resource (release or tag) by its URL if it exists.

\tArgs:
\t\tconfig:        Platform configuration
\t\turl:           Full URL of the resource
\t\tresource_name: Name for logging (e.g., "release", "tag")
\t'''
def delete_resource_unconditional(config: PlatformConfig, url: str, resource_name: str) -> None:
    ''' Delete a resource without checking if it exists first.

\tArgs:
\t\tconfig:        Platform configuration
\t\turl:           Full URL of the resource
\t\tresource_name: Name for logging (e.g., "release", "tag")
\t'''
def create_tag_on_branch(config: PlatformConfig, tags_url: str, create_tag_data: Callable[[str], dict[str, str]], branches: list[str] | None = None) -> None:
    ''' Create a tag, trying multiple branch names if needed.

\tArgs:
\t\tconfig:          Platform configuration
\t\ttags_url:        API URL for creating tags
\t\tcreate_tag_data: Function to create tag request data given a branch name
\t\tbranches:        List of branch names to try (default: ["main", "master"])
\t'''
def create_release(config: PlatformConfig, release_data: dict[str, Any]) -> dict[str, Any]:
    """ Create a release.

\tArgs:
\t\tconfig:       Platform configuration
\t\trelease_data: Release request data
\tReturns:
\t\tdict: Response JSON from the API
\t"""
