from abc import ABC
from .. api_workers.tg_handle import Bot
import time
import math
from py_progress.progress import ProgressBar
import requests
from .. utils.proxies_getter import Proxy
import threading
from .. config import BASE_URL



class Downloader(ABC):
    def __init__(self, bot, proxies):
        self.bot: Bot = bot
        self.proxies: list[Proxy] = proxies
        self.session = requests.Session()


    def download_block(self, url, index, proxy_index):

        self.q_count += 1
        durl, status_link = self.bot.get_download_link(url)

        try:
            response = self.session.get(durl, proxies=self.proxies[proxy_index].proxy_link, timeout=None)

            self.current_blocks.append([index, response.content])
            self.q_count -= 1
            self.pb.progress_with_time("")
            if self.progress_fun is not None:
                self.progress_fun(math.ceil((self.pb.procent / self.pb.all)  * 100), "download")

        except:
            self.proxies.pop(proxy_index)
            self.add_to_curr_proxy()
            print("del")
            self.download_block(url, index, self.curr_proxy_index)


    def sort_blocks(self, blocks):
        sort_blocks = blocks.copy()
        for i in range(len(blocks)):
            for j in range(len(blocks) - 1):
                if sort_blocks[j][0] > sort_blocks[j + 1][0]:
                    sort_blocks[j], sort_blocks[j + 1] = sort_blocks[j + 1], sort_blocks[j]
        return sort_blocks
    
    def wating_blocks(self):
        while True:
            if len(self.current_blocks) <= 1:
                break

            time.sleep(1)

    def queue_wating(self, max_blocks):
        while True:
            if self.q_count <= max_blocks:
                break

            time.sleep(1)

    def final_pool_blocks_with_q(self, file_path):
        
        all_sorted_blocks = self.sort_blocks(self.current_blocks)
        check_line_sorted = []
        if len(all_sorted_blocks) > 0:

            for i, el in enumerate(all_sorted_blocks):
                if i > 0:
                    if all_sorted_blocks[i-1][0] + 1 != el[0]:
                        break

                check_line_sorted.append(el)
            

            if check_line_sorted[0][0] == self.last_index + 1:
                for i, el in enumerate(check_line_sorted):
                    
                    with open(file_path, "ab") as f:
                        f.write(el[1])


                self.last_index = check_line_sorted[-1][0]
                self.current_blocks = all_sorted_blocks[len(check_line_sorted):]

    def add_to_curr_proxy(self):
        if self.curr_proxy_index >= len(self.proxies) - 1:
            self.curr_proxy_index = 0
        else:
            self.curr_proxy_index += 1

    def download(self, files_id, file_path, max_blocks_pool=10, progress_fun=None, full_check_in=50):
        self.pb = ProgressBar(math.ceil(len(files_id)))
       
        self.curr_proxy_index = 0

        self.current_blocks = []
        self.q_count = 0
        self.last_index = -1
        self.progress_fun = progress_fun

        for i in range(len(files_id)):
            #choese proxy
            # curr_proxy = self.proxies[curr_proxy_index]
            

            #start_block
            down = threading.Thread(target=self.download_block, args=(files_id[i], i, self.curr_proxy_index))
            down.start()

            self.add_to_curr_proxy()

            self.queue_wating(max_blocks_pool)
            self.final_pool_blocks_with_q(file_path)
            if i % full_check_in == 0:
                while self.q_count > 0:
                    time.sleep(1)


        while self.q_count > 0:
            time.sleep(1)
        self.final_pool_blocks_with_q(file_path)



   




