import time
import math

def humanbytes(size):
    if not size:
        return ""
    power = 2**10
    n = 0
    Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'}
    while size > power:
        size /= power
        n += 1
    return str(round(size, 2)) + " " + Dic_powerN[n] + 'B'

def time_formatter(seconds: int) -> str:
    minutes, seconds = divmod(seconds, 60)
    hours, minutes = divmod(minutes, 60)
    days, hours = divmod(hours, 24)
    tmp = ((str(days) + "d, ") if days else "") + \
          ((str(hours) + "h, ") if hours else "") + \
          ((str(minutes) + "m, ") if minutes else "") + \
          ((str(seconds) + "s") if seconds else "")
    return tmp[:-2] if tmp.endswith(", ") else tmp

async def progress_bar(current, total, status_msg, start_time, action_type="Uploading"):
    now = time.time()
    diff = now - start_time
    
    # Only update every 5 seconds or if complete to avoid flood wait
    if round(diff % 5.00) == 0 or current == total:
        percentage = current * 100 / total
        speed = current / diff if diff > 0 else 0
        elapsed_time = round(diff) * 1000
        time_to_completion = round((total - current) / speed) * 1000 if speed > 0 else 0
        estimated_total_time = elapsed_time + time_to_completion

        elapsed_time = time_formatter(int(elapsed_time / 1000))
        estimated_total_time = time_formatter(int(estimated_total_time / 1000))

        progress = "[{0}{1}] \n**Progress**: {2}%\n".format(
            ''.join(["●" for i in range(math.floor(percentage / 10))]),
            ''.join(["○" for i in range(10 - math.floor(percentage / 10))]),
            round(percentage, 2))

        tmp = progress + "**{0}**: {1}\n**Speed**: {2}/s\n**ETA**: {3}".format(
            action_type,
            humanbytes(current),
            humanbytes(speed),
            estimated_total_time if estimated_total_time != '' else "0 s"
        )
        
        try:
            await status_msg.edit(text=f"{action_type}...\n{tmp}")
        except Exception:
            pass

class ProgressFileReader:
    """Wrapper for file object to trigger progress callback during upload."""
    def __init__(self, filename, callback):
        self._file = open(filename, 'rb')
        self._callback = callback
        self._total = os.path.getsize(filename)
        self._current = 0

    def __iter__(self):
        return self

    def __next__(self):
        data = self.read(64 * 1024) # Read in 64kb chunks
        if not data:
            raise StopIteration
        return data

    def read(self, size=-1):
        data = self._file.read(size)
        self._current += len(data)
        # Call the async callback (hacky via asyncio logic in main or basic print)
        # Note: aiohttp doesn't support async generators easily for form data in old versions
        # We will handle progress updating inside the read cycle if possible, 
        # but for simplicity in aiohttp, we usually just let it stream.
        # To strictly support upload progress bars with aiohttp, we need a custom stream.
        if self._callback:
             self._callback(self._current, self._total)
        return data

    def close(self):
        self._file.close()

import os