# import redis
import concurrent.futures
import HelperFunctions
import threading
import time
import psycopg2
import socket
import subprocess
import urllib.parse
import DBStuff
import os

def ThreadedCheckFiltersPremium(result_json,
    individual_skins_set,
    inspect_link_list,
    bulk_response, 
    ReqManager,
    steamid,
    queryid,
    found_skins,
    lock,
):
    with concurrent.futures.ThreadPoolExecutor(max_workers=len(individual_skins_set)) as executor:
        futures = []
        for individual_skin in individual_skins_set:
            futures.append(
                executor.submit(
                    checkFiltersPremium,
                    result_json=result_json,
                    individual_skin=individual_skin,
                    inspect_link_list=inspect_link_list,
                    bulk_response=bulk_response,
                    ReqManager=ReqManager,
                    steamid=steamid,
                    queryid=queryid,
                    found_skins=found_skins,
                    lock=lock,
                )
            )

        for future in concurrent.futures.as_completed(futures):
            lock.acquire()
            try:
                # print("Future done")
                found_skins += int(future.result(timeout=10))
            except TimeoutError:
                print("Timed out, continue")
                # lock.release()
                continue
            except Exception as e:
                print(str(e))
                # lock.release()
                continue
            finally:
                lock.release()
    return found_skins

def checkFiltersPremium(result_json,
    individual_skin,
    inspect_link_list,
    bulk_response, 
    ReqManager,
    steamid,
    queryid,
    found_skins,
    lock,
):
    all_premium_ranks_list = []
    #for individual_skin in individual_skins_set:
    checked = checkPremiumRank(individual_skin, result_json["pages"], steamid, queryid)

    #for individual_skin in individual_skins_set:
    for page in range(int(result_json["pages"])):
        premium_ranks = getPremiumRanks(individual_skin, page, steamid, queryid)
        if premium_ranks is not None:
            if len(premium_ranks) > 0:
                all_premium_ranks_list.append(premium_ranks)

    for premium_ranks in all_premium_ranks_list:
        for inspect_link in premium_ranks:
            skin = str(inspect_link).split("%20M")[1].split("A")[1].split("D")[0]
            price = None
            page = None
            for i in inspect_link_list:
                if str(i["link"]) == str(inspect_link):
                    page = i["page"]
                    if "price" in result_json:
                        price = i["price"]
            
            rank = premium_ranks[inspect_link]
            all_filters_match = checkFilters(
                result_json=result_json,
                iteminfo=bulk_response[str(skin)],
                price=price,
            )

            stickertext = ""
            if "stickerpanel" in result_json:
                if len(bulk_response[str(skin)]["stickers"]) > 0:
                    for sticker in bulk_response[str(skin)]["stickers"]:
                        try:
                            stickertext += str(sticker["name"]) + ", "
                        except Exception as e:
                            print(str(e))
                            continue
                    stickertext = str(stickertext)[:-2]
            if all_filters_match is True and rank is not None and int(rank) <= int(result_json["csfloat_rank"]):
                DBStuff.handleDBInsert(
                    bulk_response[str(skin)]["full_item_name"],
                    bulk_response[str(skin)]["floatvalue"],
                    bulk_response[str(skin)]["paintseed"],
                    inspect_link,
                    price,
                    page,
                    stickertext,
                    rank,
                    steamid,
                    queryid,
                    result_json,
                )
                with lock:
                    found_skins += 1
    return found_skins



def threadedFilterSkins(
    result_json,
    inspect_link_list,
    bulk_response,
    skin,
    ReqManager,
    steamid,
    queryid,
    conn,
    lock,
):
    if "error" in bulk_response[str(skin)] or "error" in bulk_response:
        return 0
    found_skins = 0
    generated_inspect_link = HelperFunctions.generateInspectLink(
        bulk_response[str(skin)]["m"],
        bulk_response[str(skin)]["s"],
        bulk_response[str(skin)]["a"],
        bulk_response[str(skin)]["d"],
    )
    if "price" in result_json:
        price = HelperFunctions.getPrice(inspect_link_list, bulk_response[str(skin)])
    else:
        price = None

    try:
        page = HelperFunctions.getPage(inspect_link_list, bulk_response[str(skin)])
    except Exception as e:
        print(str(e))

    all_filters_match = checkFilters(
        result_json=result_json,
        iteminfo=bulk_response[str(skin)],
        price=price,
    )

    stickertext = ""
    if "stickerpanel" in result_json:
        if len(bulk_response[str(skin)]["stickers"]) > 0:
            for sticker in bulk_response[str(skin)]["stickers"]:
                try:
                    stickertext += str(sticker["name"]) + ", "
                except Exception as e:
                    print(str(e))
                    continue
            stickertext = str(stickertext)[:-2]
    

    rank = None
    if "maxfloatrank" in result_json:
        if result_json["maxfloatrank"] == "top5":
            rank = checkDBForRank(bulk_response[str(skin)], conn)
            if all_filters_match is True and rank is not None:
                DBStuff.handleDBInsert(
                    bulk_response[str(skin)]["full_item_name"],
                    bulk_response[str(skin)]["floatvalue"],
                    bulk_response[str(skin)]["paintseed"],
                    generated_inspect_link,
                    price,
                    page,
                    stickertext,
                    rank,
                    steamid,
                    queryid,
                    result_json,
                )
                with lock:
                    found_skins += 1
    else:
        if all_filters_match is True:
            DBStuff.handleDBInsert(
                bulk_response[str(skin)]["full_item_name"],
                bulk_response[str(skin)]["floatvalue"],
                bulk_response[str(skin)]["paintseed"],
                str(generated_inspect_link),
                price,
                page,
                stickertext,
                None,
                steamid,
                queryid,
                result_json,
            )
            with lock:
                found_skins += 1
    return found_skins


def filterSkins(
    result_json, inspect_link_list, inspect_server_url, ReqManager, steamid, queryid
):
    lock = threading.Lock()
    conn = psycopg2.connect(
        database="postgres",
        user="postgres",
        password="Berufsorientierung1!",
        host="23.88.122.57",
        port="5432",
    )

    bulk_inspect_link_lists = HelperFunctions.bulkAction(inspect_link_list)
    end = False
    found_skins = 0
    
    
    if "more_filters" in result_json:
        if "rank" in result_json["more_filters"]:
            if result_json["maxfloatrank"] == "csfloat_rank":
                individual_skins_set = set()
                premium_bulk_response = {}
                repeat_counter = 0
                for bulk_list in bulk_inspect_link_lists:
                        repeat_counter += 1
                        if repeat_counter > 10:
                            end = True
                        try:
                            bulk_response = ReqManager.postRequestNaked(
                                inspect_server_url + "bulk", bulk_list
                            ).json()
                        except Exception as e:
                            print(str(e))
                            time.sleep(1)
                            continue

                        for skin in bulk_response:
                            premium_bulk_response[str(skin)] = bulk_response[str(skin)]
                            individual_skins_set.add(str(bulk_response[str(skin)]["full_item_name"]))
                found_skins += ThreadedCheckFiltersPremium(result_json, individual_skins_set, inspect_link_list, premium_bulk_response, ReqManager, steamid, queryid, found_skins, lock)
                return found_skins


    repeat_counter = 0
    while not end:
        for bulk_list in bulk_inspect_link_lists:
            real_bulk_response = {}
            real_flag = False
            repeat_counter += 1
            if repeat_counter > 10:
                end = True
            try:
                bulk_response = ReqManager.postRequestNaked(
                    inspect_server_url + "bulk", bulk_list
                ).json()
            except Exception as e:
                print(str(e))
                time.sleep(1)
                continue
            # if "more_filters" in result_json:
            #     if "rank" in result_json["more_filters"]:
            # for skin in bulk_response:
            #     if "item_name" in bulk_response[str(skin)]:
            #         if (
            #             str(bulk_response[str(skin)]["item_name"])
            #             == "Gamma Doppler"
            #             or str(bulk_response[str(skin)]["item_name"]) == "Doppler"
            #         ):
            #             continue
            #         else:
            #             real_bulk_response[str(skin)] = bulk_response[str(skin)]

            with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
                futures = []
                for skin in bulk_response:
                    futures.append(
                        executor.submit(
                            threadedFilterSkins,
                            result_json=result_json,
                            inspect_link_list=inspect_link_list,
                            bulk_response=bulk_response,
                            skin=skin,
                            ReqManager=ReqManager,
                            steamid=steamid,
                            queryid=queryid,
                            conn=conn,
                            lock=lock,
                        )
                    )

            for future in concurrent.futures.as_completed(futures):
                lock.acquire()
                try:
                    # print("Future done")
                    found_skins += int(future.result(timeout=10))
                except TimeoutError:
                    print("Timed out, continue")
                    # lock.release()
                    continue
                except Exception as e:
                    print(str(e))
                    # lock.release()
                    continue
                finally:
                    lock.release()
            print("Threadpool Done")
        end = True
        continue
    
    return found_skins


def checkDBForRank(iteminfo, conn):
    cursor = conn.cursor()
    cursor.execute(
        "SELECT float, rank FROM full_floats_low WHERE market_hash_name = %s",
        (str(iteminfo["full_item_name"]),),
    )
    top5_low = cursor.fetchall()

    cursor.execute(
        "SELECT float, rank FROM full_floats_high WHERE market_hash_name = %s",
        (str(iteminfo["full_item_name"]),),
    )
    top5_high = cursor.fetchall()

    if len(top5_low) == 0 and len(top5_high) == 0:
        return None

    for topfloat in top5_high:
        if float(iteminfo["floatvalue"]) > float(topfloat[0]):
            print(
                "ACTUAL TOP 5 HIGHFLOAT FOUND FOR: " + str(iteminfo["full_item_name"])
            )
            return topfloat[1]

    for topfloat in top5_low:
        if float(iteminfo["floatvalue"]) < float(topfloat[0]):
            print("ACTUAL TOP 5 LOWFLOAT FOUND FOR: " + str(iteminfo["full_item_name"]))
            return topfloat[1]
    cursor.close()
    return None

def checkPremiumRank(full_item_name, pages, steamid, queryid):
    if HelperFunctions.isOpen("23.88.122.57", 8021) and HelperFunctions.isOpen("23.88.122.57", 9981):
        subprocess.run(["python3", "main.py", full_item_name, str(pages), str(steamid), str(queryid)], cwd="/var/www/premiumrankchecker")
    else:
        return None

def getPremiumRanks(full_item_name, page, steamid, queryid):
    csfloat_ranks = {}
    results_list = open("/var/www/premiumrankchecker/rank_txts/" + str(queryid) + "_" + str(steamid) + "_" + urllib.parse.quote(str(full_item_name)) + "_" + str(page) + ".txt", "r")
    lines = results_list.readlines()
    #os.remove("/var/www/premiumrankchecker/rank_txts/" + urllib.parse.quote(str(full_item_name)) + "_" + str(page) + ".txt")
    #results_list = f.readline()[1:-1]
    try:
        result = lines[0].split("],")
        for res in result:
            inspect_link = res.split("'")[1]
            rank = res.split("'")[3]
            csfloat_ranks[str(inspect_link)] = rank
        #os.remove("/var/www/premiumrankchecker/rank_txts/" + urllib.parse.quote(str(full_item_name)) + "_" + str(page) + ".txt")
        return csfloat_ranks
    except Exception as e:
        return None



def checkForLowFloatSIHRank(result_json, iteminfo, ReqManager):
    inspect_link = HelperFunctions.generateInspectLink(
        iteminfo["m"], iteminfo["s"], iteminfo["a"], iteminfo["d"]
    )
    full_url = "https://floats.steaminventoryhelper.com/?url=" + str(inspect_link)

    end = False
    while not end:
        response = ReqManager.getIPRoyalRequest(full_url)
        if response is None:
            return [None, None]
        try:
            response_json = response.json()
        except Exception as e:
            print(str(e))
        end = True
        if response_json is None:
            return [None, None]
        if "error" in response_json:
            return [None, None]

    if "iteminfo" in response_json:
        if (
            response_json["iteminfo"]["globalRatingPos"] != "null"
            and response_json["iteminfo"]["globalRatingPos"] is not None
        ):
            global_rank = float(response_json["iteminfo"]["globalRatingPos"])
            if global_rank < 0:
                return [None, None]
            #     global_rank = abs(int(global_rank))
            #     if global_rank <= result_json["rank"]:
            #         return [global_rank, None]
            else:
                global_rank = int(global_rank)
                if global_rank <= 5:
                    return [None, global_rank]

        if (
            response_json["iteminfo"]["localRatingPos"] != "null"
            and response_json["iteminfo"]["localRatingPos"] is not None
        ):
            local_rank = float(response_json["iteminfo"]["localRatingPos"])
            if local_rank < 0:
                # local_rank = abs(int(local_rank))
                # if local_rank <= result_json["rank"]:
                #     return [local_rank, None]
                return [None, None]
            else:
                local_rank = int(local_rank)
                if local_rank <= 5:
                    return [None, local_rank]

    return [None, None]


def checkFilters(result_json, iteminfo, price):
    
    filters_dict = {}

    if result_json["filter_options"] == "exact_float":
        filters_dict["exact_float"] = False
        if len(str(result_json["exact_float"])) == len(str(iteminfo["floatvalue"])):
            if float(result_json["exact_float"]) == float(iteminfo["floatvalue"]):
                filters_dict["exact_float"] = True
        else:
            cut_iteminfo_float = float(str(iteminfo["floatvalue"])[:-3])
            # print(float(result_json["exact_float"]))
            # print(cut_iteminfo_float)
            if float(result_json["exact_float"]) == cut_iteminfo_float:
                filters_dict["exact_float"] = True

    if result_json["filter_options"] == "float_restrictions":
        if result_json["float_restrictions"] == "starts_with":
            filters_dict["starts_with"] = False
            if str(iteminfo["floatvalue"]).startswith(
                str(result_json["float_for_restriction"])
            ):
                filters_dict["starts_with"] = True

        if result_json["float_restrictions"] == "is_bigger":
            filters_dict["is_bigger"] = False
            if float(result_json["float_for_restriction"]) < float(
                iteminfo["floatvalue"]
            ):
                filters_dict["is_bigger"] = True

        if result_json["float_restrictions"] == "is_smaller":
            filters_dict["is_smaller"] = False
            if float(result_json["float_for_restriction"]) > float(
                iteminfo["floatvalue"]
            ):
                filters_dict["is_smaller"] = True

    if "pattern" in result_json:
        filters_dict["pattern"] = False
        if int(result_json["pattern"]) == int(iteminfo["paintseed"]):
            filters_dict["pattern"] = True

    if "price" in result_json:
        filters_dict["price"] = False
        if float(price) <= float(result_json["price"]):
            filters_dict["price"] = True

    if "stickerpanel" in result_json:
        filters_dict["stickers"] = False
        stickerlist_wanted = result_json["stickerpanel"]
        stickerlist_wanted_names_only = []
        stickerlist_received = iteminfo["stickers"]
        stickerlist_received_names_only = []

        for sticker in stickerlist_wanted:
            stickerlist_wanted_names_only.append(str(sticker["sticker"]))

        for sticker in stickerlist_received:
            stickerlist_received_names_only.append(str(sticker["name"]))

        matching_sticker_count = 0
        for wanted_sticker in stickerlist_wanted_names_only:
            for current_sticker in stickerlist_received_names_only:
                if wanted_sticker == current_sticker:
                    matching_sticker_count += 1

        if len(stickerlist_wanted_names_only) == matching_sticker_count:
            filters_dict["stickers"] = True

    for f in filters_dict:
        if filters_dict[f] is False:
            return False

    return True
