import os
import time
import requests
from tools.log import logger
from tools.utils import Utils


class FileDownloader:
    def __init__(self, url, local_filename, max_retries=1):
        self.url = url
        self.local_filename = local_filename
        self.max_retries = max_retries
        self.chunk_size = 8192  # 每块数据大小 (8 KB)
        self.timer = Utils.Timer()
        self.last_logged_time = 0
        self.last_logged_size = 0
        self.total_size = 0

    def download(self, resume=True):
        retry_count = 0
        retry_delay = 2

        while retry_count <= self.max_retries:
            try:
                return self._download(resume)
            except requests.RequestException as e:
                retry_count += 1
                logger.error(f"Download failed: {e}. Retrying {retry_count}/{self.max_retries} after {retry_delay}s...")
                time.sleep(retry_delay)
                retry_delay *= 2  # 指数退避

        raise Exception(f"Failed to download {self.url} after {self.max_retries} retries")

    def _download(self, resume):
        resume_header = {}
        downloaded_size = 0

        # 检查是否需要断点续传
        if resume and os.path.exists(self.local_filename):
            downloaded_size = os.path.getsize(self.local_filename)
            resume_header = {'Range': f'bytes={downloaded_size}-'}
            logger.info(f"Resuming download from byte: {downloaded_size}")
        else:
            logger.info("Starting new download.")

        # 发起请求
        with requests.get(self.url, headers=resume_header, stream=True, timeout=30) as response:
            response.raise_for_status()
            self.total_size = int(response.headers.get('Content-Length', 0)) + downloaded_size

            with open(self.local_filename, 'ab') as f:
                start_time = time.time()
                previous_time = start_time

                for chunk in response.iter_content(chunk_size=self.chunk_size):
                    if not chunk:  # 忽略空数据块
                        continue

                    f.write(chunk)
                    downloaded_size += len(chunk)

                    current_time = time.time()
                    time_elapsed = int(current_time - previous_time)

                    # 每隔 1 秒更新日志
                    if time_elapsed >= 1 or self.timer.timer("download", 5):
                        self._log_progress(downloaded_size, self.total_size, start_time, previous_time)
                        previous_time = current_time

        logger.info(f"Download completed: {self.local_filename}")

    def _log_progress(self, downloaded_size, total_size, start_time, previous_time):
        """
        输出下载进度日志，包含当前进度和下载速度。

        :param downloaded_size: 已下载大小（字节）
        :param total_size: 文件总大小（字节）
        :param start_time: 下载开始时间
        :param previous_time: 上一次记录日志的时间
        """
        percent = (downloaded_size / total_size) * 100
        elapsed_time = time.time() - start_time
        interval_time = time.time() - previous_time

        # 计算平均速度和瞬时速度
        average_speed = downloaded_size / elapsed_time if elapsed_time > 0 else 0
        instant_speed = (downloaded_size - self.last_logged_size) / interval_time if interval_time > 0 else 0

        # 转换为 MB/s
        average_speed_mb = average_speed / 1024 / 1024
        instant_speed_mb = instant_speed / 1024 / 1024

        logger.info(f"{os.path.basename(self.local_filename)} - Downloaded: "
                    f"{downloaded_size / 1024 / 1024:.1f}MB of {total_size / 1024 / 1024:.1f}MB "
                    f"({percent:.2f}%) | {instant_speed_mb:.2f} MB/s")

        # 更新记录的时间和大小
        self.last_logged_time = time.time()
        self.last_logged_size = downloaded_size
