import time
import subprocess
import threading
import socket
import traceback
import urllib.request
import json
from datetime import datetime

import pytz
import requests

PORT = 443
CHECK_INTERVAL = 120  # sec
BLOCK_DURATION = 2800  # 30 minutes
INCREASE_THRESHOLD = 200
TOP_IP_COUNT = 50

previous_counts = {}
blocked_ips = {}

# رنگ‌ها
RED = "\033[91m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
BLUE = "\033[94m"
RESET = "\033[0m"
BOLD = "\033[1m"


def sleep_with_countdown(seconds):
    for remaining in range(seconds, 0, -1):
        print(f"{YELLOW} Waiting... {remaining} seconds remaining...{RESET}", end="\r")
        time.sleep(1)
    print(" " * 60, end="\r")  # Clear line after countdown


def get_ip_counts():
    cmd = f"ss -tn sport = :{PORT} | awk '{{print $5}}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -n {TOP_IP_COUNT}"
    result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    lines = result.stdout.decode().strip().split("\n")
    counts = {}
    for line in lines:
        parts = line.strip().split()
        if len(parts) == 2:
            count, ip = parts
            counts[ip] = int(count)
    return counts

def get_asn_info(ip):
    try:
        response = requests.get(f"http://ip-api.com/json/{ip}?fields=as,isp,country", timeout=5)
        data = response.json()
        asn = data.get("as", "Unknown")
        provider = data.get("isp", "Unknown")
        country = data.get("country", "Unknown")
        return asn, provider, country
    except Exception:
        return "Unknown", "Unknown", "Unknown"


def block(ip, asn_info):
    asn, provider, country = asn_info

    if country == "IR" or country == "Iran":
        print(f"{YELLOW}[SKIP] Skipped blocking {ip} (ASN: {asn} | {provider}){RESET}")
        return

    subprocess.call(["iptables", "-A", "INPUT", "-s", ip, "-j", "DROP"])
    text = f"{RED}{BOLD}[X] Blocked {ip} (ASN: {asn} | {provider} | Country: {country}) for {BLOCK_DURATION // 60} min{RESET}"
    print(text)
    blocked_ips[ip] = time.time()

    def unblock():
        # اگر ASN یا provider مربوط به مورد خاص بود، انبلاک نکن
        if asn == "AS20473" or "The Constant Company" in provider:
            print(f"{YELLOW}[SKIP UNBLOCK] Did not unblock {ip} (ASN: {asn} | {provider}){RESET}")
            return

        time.sleep(BLOCK_DURATION)
        subprocess.call(["iptables", "-D", "INPUT", "-s", ip, "-j", "DROP"])
        print(f"{GREEN}[-] Unblocked {ip} after {BLOCK_DURATION // 60} min{RESET}")
        blocked_ips.pop(ip, None)


    threading.Thread(target=unblock).start()




def main():
    global previous_counts

    now_tehran = datetime.now(pytz.timezone("Asia/Tehran")).strftime("%Y-%m-%d %H:%M:%S")
    print(f"{BLUE}[{now_tehran}] Checking IP connections on port {PORT}...{RESET}")
    initial_counts = get_ip_counts()
    top_10 = sorted(initial_counts.items(), key=lambda x: x[1], reverse=True)[:10]
    for ip, count in top_10:
        if ip not in blocked_ips:
            asn_info = get_asn_info(ip)
            block(ip, asn_info)

    previous_counts = get_ip_counts()
    sleep_with_countdown(CHECK_INTERVAL)

    while True:
        now_tehran = datetime.now(pytz.timezone("Asia/Tehran")).strftime("%Y-%m-%d %H:%M:%S")
        print(f"{BLUE}[{now_tehran}] Checking IP connections on port {PORT}...{RESET}")
        current_counts = get_ip_counts()
        for ip, new_count in current_counts.items():
            old_count = previous_counts.get(ip, 0)
            if new_count - old_count > INCREASE_THRESHOLD and ip not in blocked_ips:
                asn_info = get_asn_info(ip)
                block(ip, asn_info)
        previous_counts = current_counts
        sleep_with_countdown(CHECK_INTERVAL)


if __name__ == "__main__":
    main()
