from calendar import Calendar, calendar
from itertools import chain, count
from random import Random, randint, random
from select import select
import time
import requests
import os
import calendar
import datetime
import runpy
import time
from collections import Counter
import os.path
from datetime import datetime, timedelta, date
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import email.utils
import traceback
from contextlib import closing
from config import get_database_config, get_config, DatabaseConnection
from sendmail import sendExceptionMail


actual_server_number = 1
server_num = (actual_server_number - 1)
total_servers = 2
MAX_BATCH_SIZE = 10 

log_file_path = "script_log.txt"
def log(message):
    with open(log_file_path, "a") as log_file:
        log_file.write(message + "\n")

def format_time_difference(seconds):
    td = timedelta(seconds=seconds)
    hours, remainder = divmod(td.seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    return f"{hours:02}:{minutes:02}:{seconds:02}"

#---DATABASE_CONNECTION---
# environment = 'staging' #production, staging, local
environment_selected, config = get_config()
print(environment_selected)

# Host Details
live_ovpn_table_name = config["ovpn_table_name"]
live_country_table_name = config["country_table_name"]
decode_vpn_path = "decodeOvpn/"
ovpn_path = config["ovpn_main_file_path"]
connection_php_path = config["connection_php_path"]

#script details

abs_path = os.path.abspath(__file__)
full_script_name = environment_selected.upper() + " " + os.path.basename(abs_path)
server_ip = config["server_ip"]

#---DATABASE_CONFIG---
db_config = get_database_config(config) 

print(full_script_name, server_ip)

def update_script_run_counter():
    counter_file_path = "script_run_counter.txt"

    # Check if the counter file exists
    if not os.path.exists(counter_file_path):
        # If the file doesn't exist, create it and initialize the counter to 1
        with open(counter_file_path, "w") as counter_file:
            counter_file.write("1")
        return 1
    else:
        # If the file exists, read the current counter value, increment it, and update the file
        with open(counter_file_path, "r+") as counter_file:
            counter = int(counter_file.read())
            counter += 1
            counter_file.seek(0)
            counter_file.write(str(counter))
        return counter


def ovpnConnected(filepath):
    url = connection_php_path

    # Assuming the API expects the 'filepath' parameter
    payload = {"filepath": filepath}

    response = requests.post(url, data=payload) 
    print(response)
    if response.status_code == 200:
        data = response.json()
        return data["isConnected"]
    else:
        return f"Error: {response.status_code}, {response.text}"

def checking_servers():
    try:
        # Get the current script run counter
        # script_run_count = update_script_run_counter()

        # print(f"This is the {script_run_count}th time the script has run.")
        db = DatabaseConnection(db_config)
        db.connect()
        update_queries = []  # List to store update queries
        db.execute_query(f"SELECT COUNT(*) as total_count FROM {live_ovpn_table_name}")
        total_rows = db.fetch_one()["total_count"]

        # Calculate the number of rows each server should handle
        rows_per_server = total_rows // total_servers
        remaining_rows = total_rows % total_servers
        # Define a function to process rows for a given server

        offset = server_num * rows_per_server
        limit = rows_per_server + (1 if server_num < remaining_rows else 0)

        print(f"server limit: {limit}")
        print(f"server offset: {offset}")

        db.execute_query(f"SELECT ip_address, server_id, ping_count, ovpn ,connect ,disconnect ,total_connection FROM {live_ovpn_table_name} LIMIT {limit} OFFSET {offset}")
        ipfetch = db.fetch_all()
        print(f"Processing for server {server_num + 1}: {len(ipfetch)}")
        # exit()
        db.close()
        # print(ipfetch)
        # exit()
        if ipfetch != ():
            for iplist in ipfetch:
                if iplist:
                    ip_address = iplist["ip_address"]
                    server_id = iplist["server_id"]
                    pingCount = iplist["ping_count"]
                    connect_server = iplist["connect"]
                    disconnect_server = iplist["disconnect"]
                    total_connection = iplist["total_connection"]

                    print('connect,disconnect,total_connection',connect_server,disconnect_server,total_connection)

                    if total_connection != 0:
                        connect_percentage = int(connect_server/total_connection*100)
                    else:
                        connect_percentage = 0
                    print('connect_percentage : ',connect_percentage)

                    total_connection+=1
                    print('total_connection after: ',total_connection)

                    # connection = get_database_connection(config)
                    # cursor = connection.cursor(dictionary=True)
                    # query = "select ping_count, ovpn from {} WHERE ip_address = %s AND server_id = %s".format(
                    #     live_ovpn_table_name
                    # )
                    # qr_parm = (ip_address, server_id)
                    # cursor.execute(query, qr_parm)
                    # data = cursor.fetchone()
                    # cursor.close()
                    # connection.close()

                    
                    # pingCount = iplist["ping_count"]
                    ovpn = iplist["ovpn"]

                    # filepath = ovpn_path + str(server_id) + "_" + ip_address + ".ovpn"
                    filepath = ovpn_path + ip_address + ".ovpn"
                    check_file = os.path.exists(filepath)
                    print(check_file)

                    if check_file == False:
                        with open(filepath, "w") as fh:
                            fh.write(ovpn)
                    # print("filepath", filepath)
                    response = ovpnConnected(filepath)

                    # subprocess.run(["sudo", "killall", "openvpn"])
                    print("pingcount before:", pingCount)
                    print("response: " + ip_address, response)

                    update_query = "UPDATE {} SET is_active = %s , ping_count = %s, updated_at = %s, total_connection = %s,connect = %s,disconnect = %s ,connect_percentage=%s   WHERE ip_address = %s AND server_id = %s".format(live_ovpn_table_name)

                    if response == True:
                        # print(pingCount[0][0]+1)
                        dt = time.gmtime()
                        ts = calendar.timegm(dt)
                        connect_server += 1
                        print('connect_server after',connect_server)
                        
                        update_data = (1, pingCount + 1, ts,total_connection,connect_server,disconnect_server,connect_percentage,ip_address ,server_id)
                        # a = cursor.execute(sql, ip)
                        # cursor.close()
                        # connection.commit()
                        # connection.close()
                        update_queries.append(update_data)

                    else:
                        print(pingCount)
                        print(ip_address, "is down")
                        dt = time.gmtime()
                        ts = calendar.timegm(dt)

                        disconnect_server += 1
                        print('disconnect_server after',disconnect_server)

                        update_data = (0, pingCount - 1, ts, total_connection,connect_server,disconnect_server,connect_percentage,ip_address ,server_id)
                        # a = cursor.execute(sql, ip)
                        update_queries.append(update_data)
                        # a = cursor.execute(sql, ip)
                        update_queries.append(update_data)
                        # query = "SELECT ping_count FROM {} WHERE ip_address = %s AND server_id = %s".format(
                        #     live_ovpn_table_name
                        # )
                        # ip = (ip_address, server_id)
                        # cursor.execute(query, ip)
                        # updated_ping_count = cursor.fetchone()
                        # cursor.close()
                        # connection.commit()
                        # connection.close()

                        # if updated_ping_count is not None:
                        #     print("ping count after:", updated_ping_count['ping_count'])
                        # else:
                        #     print("after ping count not found")
                    print("query batch count", len(update_queries))
                    # print("queires---->", update_queries)

                if len(update_queries) >= MAX_BATCH_SIZE:  # Update every 10 queries or at loop end
                    print(f"updating {len(update_queries)} queries------------------------------------------------------------")
                    db = DatabaseConnection(db_config)
                    db.connect()
                    db.execute_many(update_query, update_queries)
                    db.connection.commit()  # Commit changes after execution
                    db.close()
                    update_queries = []  # Clear list for next batch
            
            if update_queries:
                if update_query:
                    print(f"updating {len(update_queries)} queries------------------------------------------------------------")
                    db = DatabaseConnection(db_config)
                    db.connect()
                    db.execute_many(update_query, update_queries)
                    db.connection.commit()  # Commit changes after execution
                    db.close()
                    update_queries = []


            time.sleep(1)

    except Exception as e:
        excp = traceback.format_exc()
        print("exp------------>", str(e))
        print("tracebackk-----------------------------", excp)
        excp_time = time.time()
        excp_time_formatted = datetime.fromtimestamp(excp_time).strftime('%Y-%m-%d %H:%M:%S')
        sendExceptionMail(str(excp), full_script_name, server_ip, str(excp_time_formatted))
        time.sleep(30)
        runpy.run_path(path_name="check_server_parallely_main.py")

    finally:
        if db:
            db.close()


def main():
    run_count = 0
    
    while True:
        start_time = time.time()
        run_count += 1
        print("script_start_time", start_time)
        # Simulate function calls (replace with your actual functions)

        checking_servers()
        
        end_time = time.time()
        time_difference = end_time - start_time
        formatted_time_difference = format_time_difference(time_difference)
        print("script_end_time", end_time)
        

        log(f"Start Time script: {datetime.fromtimestamp(start_time).strftime('%Y-%m-%d %H:%M:%S')}")
        log(f"Script Run Count script: {run_count}")
        log(f"End Time script: {datetime.fromtimestamp(end_time).strftime('%Y-%m-%d %H:%M:%S')}")
        log(f"Time Difference script: {formatted_time_difference}")
        
if __name__ == "__main__":
    main()
