import threading
from abc import ABC, abstractmethod
import os
import hashlib
from .. api_workers.tg_handle import Bot
import io
import time
from py_progress.progress import ProgressBar
import requests
from .. api_workers.auth import Profile
from .. utils.proxies_getter import load_proxies, Proxy
import math
from .. config import BASE_URL




def get_random_hash(random_param=32):
    random_bytes = os.urandom(random_param)
    hash_value = hashlib.sha256(random_bytes).hexdigest()

    return hash_value



class Loader(ABC):
    def __init__(self, file, bot, profile: Profile, proxies):
        self.file = file
        self.bot: Bot = bot
        self.count_of_file = 0
        self.profile = profile
        self.proxies = proxies
        self.session = requests.Session()

    def init_global_file(self, file_path=None):
        res = self.session.post(f"{BASE_URL}/files_handler/add_global_file", cookies=self.profile.auth_cookies, data={
            "file_size": self.file_size,
            "file_name": self.file.name.split("\\")[-1],
            "file_path": file_path
        })
        res_data = res.json()
        self.upload_session_id = res_data["upload_session_id"]

    @property
    def file_size(self):
        pos = self.file.tell()
        self.file.seek(0, 2)  
        size = self.file.tell()
        self.file.seek(pos)

        return size


    def send_block(self, file_index, block, file_hash):
        self.req_in_q += 1
        while True:
            response_data = self.bot.send_block(io.BytesIO(block), f"{file_hash}", proxies=self.proxies)
            if response_data["ok"] == True:
                break
            
            print(f"this proxy doestn work: {self.bot.curr_proxy_index}")
            self.proxies.pop(self.bot.curr_proxy_index)
            self.bot.curr_proxy_index -= 1

        res_data = self.session.post(f"{BASE_URL}/files_handler/{self.upload_session_id}/add", cookies=self.profile.auth_cookies, data={
            "file_tg_hash": response_data["result"]["document"]["file_id"],
            "file_index": file_index,
            "file_size": response_data["result"]["document"]["file_size"],
        })
        self.count_of_file += 1
        self.req_in_q -= 1

        self.current_pb.progress("")
        if self.progress_fun is not None:
            self.progress_fun(self.upload_session_id, math.ceil((self.current_pb.procent / self.current_pb.all)  * 100))


    def reader(self, chunk_size):
        buffer = b''
        while chunk := self.file.read(chunk_size):
            is_last = len(chunk) < chunk_size
            chunk = buffer + chunk

            if is_last == False:

                last_index = chunk.rfind(b"\n")
                if last_index == -1:
                    buffer = b''
                else:
                    buffer = chunk[last_index + 1:]
                    chunk = chunk[:last_index + 1]
                
                
                yield chunk
            else:
                yield chunk

    def check_len(self, target_len):
        while True:
            if target_len <= self.count_of_file:
                break
            time.sleep(1)

    def check_len_queue(self, max_q):
        while True:
            if self.req_in_q <= max_q:
                break
            time.sleep(1)

    def split_info(self, block_size=10 * 1024 * 1024, send_controller=10, progress_fun=None, start_index=0, full_check_in=50):
        response_data_len = 0

        start_time = time.time()
        blocks_count = math.ceil(math.ceil(self.file_size / (block_size)))
        self.req_in_q = 0

        self.progress_fun = progress_fun
        self.current_pb = ProgressBar(blocks_count)
        self.current_pb.procent += start_index

        for i, el in enumerate(self.reader(block_size)):
            if i >= start_index:
                file_hash = get_random_hash()
                file_hash += ".bin"

                send = threading.Thread(target=self.send_block, args=(i, el, file_hash))       
                send.start()
                response_data_len += 1

                self.check_len_queue(send_controller)

                if i % full_check_in == 0:
                    self.check_len(response_data_len)




                
                    



        self.check_len(response_data_len)

        res_data = requests.post(f"{BASE_URL}/files_handler/{self.upload_session_id}/close", cookies=self.profile.auth_cookies)
        print("END")




if __name__ == "__main__":

    TOKEN = "8392027187:AAEglTR9vtwC_yYFtNZUE8zuQABBGGCJdXE"
    CHAT_ID = "1228194994"

    start_time = time.time() 
    profile = Profile("test", "test")

    proxies = load_proxies()
    with open(r"C:\Users\huina\Downloads\video_2025-08-08_13-18-11.mp4", "rb") as file:

        l = Loader(file, Bot(TOKEN, CHAT_ID), profile, proxies=proxies[:15])
        l.init_global_file()
        response_data = l.split_info(10 * 1024 * 1024, 5)

    print(l.global_file_id)
    endload_time = time.time() 

    print(f"\nupload time = {(endload_time - start_time):.2f}")
