"""Progress bar logic for the syntella app."""

import time
from typing import Optional

from app.constants import TextColor


class ProgressBar:
    """
    Handles progress bar logic, including color-coded fill/empty chars
    and building the bar string.

    :param total_steps: The total steps for 100% progress.
    :type total_steps: int
    :param bar_length: The visible length of the bar.
    :type bar_length: int
    :param fill_char: Character for the filled portion.
    :type fill_char: str
    :param empty_char: Character for the empty portion.
    :type empty_char: str
    :param prefix: Optional text before the bar.
    :type prefix: str
    :param suffix: Optional text after the bar.
    :type suffix: str
    :param fill_color: Optional color for the filled portion.
    :type fill_color: TextColor
    :param empty_color: Optional color for the empty portion.
    :type empty_color: TextColor
    :param show_eta: If True, attempts to display an ETA.
    :type show_eta: bool
    """

    def __init__(
        self,
        total_steps: int,
        bar_length: int,
        fill_char: str,
        empty_char: str,
        prefix: str,
        suffix: str,
        fill_color: TextColor,
        empty_color: TextColor,
        show_eta: bool = False
    ) -> None:
        """
        Initializes the progress bar with the given parameters.
        """
        self.total_steps = max(total_steps, 1)
        self.bar_length = bar_length
        self.fill_char = fill_char
        self.empty_char = empty_char
        self.prefix = prefix
        self.suffix = suffix
        self.fill_color = fill_color
        self.empty_color = empty_color
        self.show_eta = show_eta

        self.current_step = 0
        # For ETA
        self._start_time: Optional[float] = None

    def set_progress(self, step: int) -> None:
        """
        Sets the current progress to `step`.

        :param step: The new absolute progress value.
        :type step: int
        """
        if self._start_time is None:
            self._start_time = time.time()
        self.current_step = max(0, min(step, self.total_steps))

    def increment_progress(self, inc: int) -> None:
        """
        Increments current progress by `inc`.

        :param inc: The amount to increment.
        :type inc: int
        """
        if self._start_time is None:
            self._start_time = time.time()
        self.set_progress(self.current_step + inc)

    def reset_progress(self, total_steps: Optional[int] = None) -> None:
        """
        Resets the progress to zero. If total_steps is given, also updates
        the total step count.

        :param total_steps: If provided, sets a new total of steps.
        :type total_steps: int
        """
        self._start_time = None
        if total_steps is not None:
            self.total_steps = max(1, total_steps)
        self.current_step = 0

    def build_bar_text(self) -> str:
        """
        Builds and returns the bar string, applying fill/empty color if set.
        If `show_eta` is True, also appends an approximate ETA.

        :return: A string containing the progress bar.
        :rtype: str
        """
        fraction = self.current_step / self.total_steps
        f_length = int(self.bar_length * fraction)

        if self.fill_color != TextColor.RESET:
            filled_part = f"{self.fill_color.value}{
                self.fill_char * f_length}{TextColor.RESET.value}"
        else:
            filled_part = self.fill_char * f_length

        if self.empty_color != TextColor.RESET:
            reset_value = TextColor.RESET.value
            empty_part = f"{self.empty_color.value}" \
                f"{self.empty_char * (self.bar_length - f_length)}" \
                f"{reset_value}"
        else:
            empty_part = self.empty_char * (self.bar_length - f_length)

        percent = fraction * 100.0
        bar_str = f"{self.prefix} |{filled_part}{
            empty_part}| {percent:6.2f}% {self.suffix}".strip()

        if self.show_eta and self._start_time and self.current_step > 0:
            elapsed = time.time() - self._start_time
            steps_done = self.current_step
            steps_total = self.total_steps
            # Simple ETA calc
            est_total = elapsed / steps_done * steps_total
            eta_s = max(0, est_total - elapsed)
            mm, ss = divmod(int(eta_s), 60)
            bar_str += f"  ETA ~ {mm:02d}:{ss:02d}"  # mm:ss

        return bar_str
