import os
import time
import urllib

import requests
from requests import HTTPError, RequestException, Timeout


class OSAWeb:

    def __init__(self, core):
        self.core = core
        self.log = core.log

    def getText(self, url) -> str:
        code, data = self.getBytes(url)
        return code, data.decode("utf8") if data else ""

    def getBytes(self, url) -> bytes:
        self.log.d(f"Downloading: {url}")
        try:
            with urllib.request.urlopen(url, timeout=30) as response:
                return response.getcode(), response.read()
        except Exception as e:
            self.log.e(f"Download failed: {e}")
            return 500, None

    def getFileInDir(self, url: str, directory: str, filename: str = None) -> str:
        """Download file to directory"""
        if filename is None:
            filename = os.path.basename(url)

        file_path = os.path.join(directory, filename)
        self.core.files.mkdir(directory, parents=True)

        try:
            urllib.request.urlretrieve(url, file_path)
            self.log.d(f"Downloaded {url} to {file_path}")
            return file_path
        except Exception as e:
            self.log.e(f"Failed to download {url}: {e}")
            return None

    def getFile(self, url: str, dest_path: str, timeout: int = 45) -> bool:
        """
        Скачать файл по URL в указанную директорию.

        Совместимость с MirrorDownloader:
        - Возвращает: True при успехе, False при ошибке
        - Поддерживает таймауты
        - Проверяет целостность результата (файл существует и не пустой)

        :param url: URL файла
        :param dest_path: Полный путь для сохранения (включая имя файла)
        :param timeout: Таймаут в секундах (по умолчанию 45)
        :return: True если файл скачан и валиден, иначе False
        """
        # Создаём директорию если не существует
        dest_dir = os.path.dirname(dest_path)
        if dest_dir:
            self.core.files.mkdir(dest_dir, parents=True)

        start_time = time.time()

        try:
            # Потоковая загрузка — не грузим весь файл в память
            with requests.get(url, stream=True, timeout=timeout) as r:
                r.raise_for_status()  # Выбросит исключение для 4xx/5xx

                # Записываем чанками по 8 КБ
                with open(dest_path, 'wb') as f:
                    for chunk in r.iter_content(chunk_size=8192):
                        if chunk:  # filter out keep-alive chunks
                            f.write(chunk)

            # Проверяем, что файл реально появился и не пустой
            if not os.path.exists(dest_path):
                self.log.e(f"Файл не создан после загрузки: {dest_path}")
                return False

            file_size = os.path.getsize(dest_path)
            if file_size == 0:
                self.log.e(f"Скачан пустой файл: {dest_path}")
                os.remove(dest_path)
                return False

            elapsed = time.time() - start_time
            self.log.d(f"✓ {url} → {dest_path} ({file_size // 1024} КБ, {elapsed:.1f}с)")
            return True

        except Timeout:
            self.log.w(f"Таймаут при загрузке {url} ({timeout}с)")
            return False
        except ConnectionError as e:
            self.log.w(f"Ошибка соединения {url}: {str(e)[:80]}")
            return False
        except HTTPError as e:
            self.log.w(f"HTTP ошибка {url}: {e.response.status_code}")
            return False
        except RequestException as e:
            self.log.w(f"Ошибка запроса {url}: {str(e)[:80]}")
            return False
        except OSError as e:
            self.log.e(f"Ошибка записи {dest_path}: {e}")
            return False
        except Exception as e:
            self.log.e(f"Неизвестная ошибка при загрузке {url}: {e}")
            return False

    def check_internet(self) -> bool:
        """Check internet connection"""
        try:
            urllib.request.urlopen('http://www.google.com', timeout=5)
            return True
        except:
            return False

