"""Dependency-light atomic replacement for shared licensing persistence."""

from __future__ import annotations

import math
import os
from pathlib import Path
import time


DEFAULT_REPLACE_RETRY_COUNT = 5
DEFAULT_REPLACE_RETRY_DELAY_SECONDS = 0.05


def validate_replace_retry_parameters(
    retry_count: int,
    retry_delay_seconds: float,
) -> tuple[int, float]:
    if isinstance(retry_count, bool) or not isinstance(retry_count, int):
        raise TypeError("replace_retry_count must be an integer")
    if retry_count < 1:
        raise ValueError("replace_retry_count must be at least one")
    if isinstance(retry_delay_seconds, bool):
        raise TypeError("replace_retry_delay_seconds must be a number")
    delay = float(retry_delay_seconds)
    if not math.isfinite(delay) or delay < 0.0:
        raise ValueError("replace_retry_delay_seconds must be finite and non-negative")
    return retry_count, delay


def replace_file_with_retry(
    source: str | Path,
    destination: str | Path,
    *,
    retry_count: int = DEFAULT_REPLACE_RETRY_COUNT,
    retry_delay_seconds: float = DEFAULT_REPLACE_RETRY_DELAY_SECONDS,
) -> None:
    if isinstance(source, bytes) or not isinstance(source, (str, os.PathLike)):
        raise TypeError("source must be a string or path-like object")
    if isinstance(destination, bytes) or not isinstance(destination, (str, os.PathLike)):
        raise TypeError("destination must be a string or path-like object")
    source_path = Path(source)
    destination_path = Path(destination)
    if not source_path.name:
        raise ValueError("source must identify a file")
    if not destination_path.name:
        raise ValueError("destination must identify a file")
    count, delay = validate_replace_retry_parameters(
        retry_count,
        retry_delay_seconds,
    )
    last_error: PermissionError | None = None
    for attempt in range(count):
        try:
            os.replace(source_path, destination_path)
            return
        except PermissionError as exc:
            last_error = exc
            if attempt + 1 >= count:
                break
            time.sleep(delay * (attempt + 1))
    if last_error is not None:
        raise last_error


__all__ = [
    "DEFAULT_REPLACE_RETRY_COUNT",
    "DEFAULT_REPLACE_RETRY_DELAY_SECONDS",
    "replace_file_with_retry",
    "validate_replace_retry_parameters",
]

