"""General‑purpose helper functions."""

import re


def parse_timestamp(timestamp: str) -> int:
    """
    Convert a timestamp in 'mm:ss' or 'HH:MM:SS' format to total seconds.

    Args:
        timestamp: String in the format 'mm:ss' or 'HH:MM:SS'.

    Returns:
        Total number of seconds.

    Raises:
        ValueError: If the format is unrecognized.
    """
    parts = timestamp.strip().split(':')
    if len(parts) == 2:
        minutes, seconds = map(int, parts)
        return minutes * 60 + seconds
    elif len(parts) == 3:
        hours, minutes, seconds = map(int, parts)
        return hours * 3600 + minutes * 60 + seconds
    else:
        raise ValueError(f"Invalid timestamp format: {timestamp}")


def format_time(seconds: int) -> str:
    """
    Convert seconds to 'HH:MM:SS' format for FFmpeg.

    Args:
        seconds: Total number of seconds.

    Returns:
        Time string in 'HH:MM:SS' format.
    """
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    secs = seconds % 60
    return f"{hours:02d}:{minutes:02d}:{secs:02d}"


def sanitize_filename(name: str) -> str:
    """
    Remove characters that are problematic on common filesystems.

    This is a fallback sanitizer; the main replacement is handled by
    apply_replacement() when --replace-bad-chars is used.

    Args:
        name: Original filename candidate.

    Returns:
        Sanitized string with dangerous characters replaced by '_'.
    """
    # Replace characters that are forbidden on Windows/Linux/macOS.
    return re.sub(r'[<>:"/\\|?*]', '_', name).strip()


def apply_replacement(name: str, bad_chars: str, replacement_char: str) -> str:
    """
    Replace every occurrence of any character in bad_chars with replacement_char.

    Args:
        name: The original string.
        bad_chars: String containing all characters to replace.
        replacement_char: The character to insert.

    Returns:
        The transformed string.
    """
    if not bad_chars:
        return name
    # Build a translation table mapping each bad character to the replacement.
    translation_table = str.maketrans({c: replacement_char for c in set(bad_chars)})
    return name.translate(translation_table)


def cleanup_good_chars(name: str, good_char: str) -> str:
    """
    Clean up the filename after replacement to avoid awkward sequences.

    Steps performed:
        1. Strip leading/trailing good_char characters.
        2. Collapse consecutive good_char characters into a single one.
        3. Remove good_char characters that are adjacent to a single non‑good_char
           (i.e., pattern good_char + X + good_char becomes just X),
           and repeat this step until no more such patterns exist.
        4. After each iteration, re‑apply stripping and collapsing.

    This makes filenames more human‑readable, e.g.:
        "author_-_song" -> "author-song"
        "hello__world" -> "hello_world"
        "_hello_" -> "hello"

    Args:
        name: The string to clean (after replacement).
        good_char: The character used as replacement.

    Returns:
        The cleaned string.
    """
    # Escape the good_char for regex usage.
    escaped = re.escape(good_char)

    # Helper to collapse consecutive good chars and strip edges.
    def collapse_and_strip(s: str) -> str:
        # Collapse multiple consecutive good chars into one.
        s = re.sub(rf'{escaped}+', good_char, s)
        # Remove leading/trailing good chars.
        s = s.strip(good_char)
        return s

    # Apply stripping and collapsing initially.
    name = collapse_and_strip(name)

    # Remove patterns: good_char + X + good_char (where X is any char != good_char).
    # Repeat until no further changes.
    while True:
        # Replace pattern: good_char (non-good-char) good_char -> just the non-good-char.
        # The negative lookahead ensures X is not the good_char.
        pattern = rf'{escaped}([^{escaped}]){escaped}'
        new_name = re.sub(pattern, r'\1', name)
        if new_name == name:
            break
        name = new_name
        # Re‑apply stripping and collapsing after removal.
        name = collapse_and_strip(name)

    return name

def apply_template(template: str, placeholders: dict) -> str:
    """
    Replace placeholders in a template string with values from a dict.

    Placeholders are of the form %key (e.g., %tn, %an).
    Use %% to escape a literal percent sign.

    Args:
        template: The template string.
        placeholders: Dict mapping placeholder names to values.

    Returns:
        The rendered string.
    """
    import re
    result = []
    i = 0
    while i < len(template):
        ch = template[i]
        if ch == '%':
            if i + 1 < len(template) and template[i + 1] == '%':
                result.append('%')
                i += 2
                continue
            match = re.match(r'%([a-zA-Z]+)', template[i:])
            if match:
                key = match.group(1)
                value = placeholders.get(key, '')
                result.append(value)
                i += len(match.group(0))
            else:
                result.append(ch)
                i += 1
        else:
            result.append(ch)
            i += 1
    return ''.join(result)
