from flask import Flask,render_template
from datetime import datetime
from flask_bcrypt import Bcrypt
from flask_mail import Mail,Message
from pymongo import MongoClient
from bson.objectid import ObjectId
import logging
from logging.handlers import RotatingFileHandler
from datetime import timedelta
from threading import Thread
import logging
from logging.handlers import RotatingFileHandler
import traceback

from Opcenter import config


# from jinja2 import Markup

app = Flask(__name__)

#Latest Files - 923



#Adding the logger
def setup_logger():
    logger = logging.getLogger('my_logger')
    logger.setLevel(logging.DEBUG)

    # create rotating file handler
    handler = RotatingFileHandler('Opcenter.log', maxBytes=1024*1024, backupCount=5)
    handler.setLevel(logging.DEBUG)

    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)

    # add handler to logger
    logger.addHandler(handler)

    return logger


my_logger = setup_logger()


app.config['SECRET_KEY'] = config.SECRET_KEY

# app.config["MONGO_URI"] = "mongodb+srv://poorna:poorna@cluster0.u0uqpgf.mongodb.net/?retryWrites=true&w=majority"

# app.config["MONGO_URI"] = 'mongodb://neil:parablu@127.0.0.1:48765'

app.config["MONGO_URI"] = config.DATABASE_URI
# app.config["MONGO_URI"] = 'mongodb://neil:parablu@127.0.0.1:27017'


client = MongoClient(app.config["MONGO_URI"])

#Configuring session timeout
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=20)

# Define an error handler for 500 errors
@app.errorhandler(500)
def internal_server_error(e):
    tb = traceback.format_exc()
    my_logger.error(f"Exception occurred:\n{tb}")
    my_logger.info(e)
    # Redirect the user to the error page with a 500 status code
    return render_template('dashboard/errorpage.html', error_code=500), 500

# Define an error handler for 404 errors
@app.errorhandler(404)
def page_not_found(e):
    tb = traceback.format_exc()
    my_logger.error(f"Exception occurred:\n{tb}")
    my_logger.info(e)
    # Redirect the user to the error page with a 404 status code
    return render_template('dashboard/errorpage.html', error_code=404), 404

@app.errorhandler(Exception)
def handle_exception(e):
    # Render the error.html template with the error message
    tb = traceback.format_exc()
    my_logger.error(f"Exception occurred:\n{tb}")
    my_logger.info(e)
    my_logger.info("This is the error printinf from line 77")
    return render_template('dashboard/errorpage.html', error_code=str(e)), 500

@app.errorhandler(UnboundLocalError)
def handle_unbound_local_error(e):
    tb = traceback.format_exc()
    my_logger.error(f"Exception occurred:\n{tb}")
    my_logger.info(e)
    return render_template('dashboard/errorpage.html', error_code='UnboundLocalError: ' + "Internal Issue"), 500

@app.errorhandler(FileNotFoundError)
def handle_file_not_found_error(e):
    tb = traceback.format_exc()
    my_logger.error(f"Exception occurred:\n{tb}")
    my_logger.info(e)
    # Render the error.html template with the error message
    return render_template('dashboard/errorpage.html', error_code="File Not Found"), 404


# Add this function to disable caching
@app.after_request
def add_header(response):
    response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    response.headers['Pragma'] = 'no-cache'
    response.headers['Expires'] = '0'
    response.headers['Cache-Control'] = 'public, max-age=0'
    return response

# Route that raises an exception
@app.route('/error')
def error():
    raise Exception("Exception Test")


# define a custom filter function
def lstrip_zero(value):
    return str(value).lstrip('0')

def bytes_to_gb(bytes):
    totalMb = int(bytes)
    totalGb = totalMb/1024
    print("The total value of totalMB is")
    print(totalMb)
    if totalGb > 0:
        return str(round(totalGb,2)) + " GB"
    else:
        return bytes    

def format_date(date_str):
    date_obj = datetime.strptime(date_str, '%Y/%m/%d %H:%M:%S')
    formatted_date = datetime.strftime(date_obj, '%d %b %Y %H:%M')
    return formatted_date

def add_space(value):
    digits = ''.join(filter(str.isdigit, value))
    letter = ''.join(filter(str.isalpha, value))
    return f"{digits} {letter}"

def filesize_fmt(value):
    size_in_bytes = float(value.split()[0])
    value = float(size_in_bytes)
    units = ['B', 'KB', 'MB', 'GB']
    for unit in units:
        if value < 1024.0:
            return f"{value:.2f} {unit}"
        value /= 1024.0
    return f"{value:.2f} {units[-1]}"


def filesize_fmt1(value):
    value = float(value)
    units = ['MB', 'GB']
    for unit in units:
        if value < 1024.0:
            return f"{value:.2f} {unit}"
        value /= 1024.0
    return f"{value:.2f} {units[-1]}"



def format_date2(date_str):
    date_str = date_str.replace('IST', '+0530')
    date_obj = datetime.strptime(date_str, '%a %b %d %H:%M:%S %z %Y')
    formatted_date2 = datetime.strftime(date_obj, '%b %d %Y %H:%M')
    return formatted_date2
 

def add_comma(value):
    if isinstance(value, int) and value >= 1000:
        value_str = str(value)
        return '{},{}'.format(value_str[:-3], value_str[-3:])
    return value


def gb_to_tb(value):
    if isinstance(value, str) and value.endswith(' GB'):
        gb_value = float(value[:-3])
        if gb_value > 1024:
            tb_value = gb_value / 1024
            return '{:.2f} TB'.format(tb_value)
    return value

def kb_to_tb(value):
    if isinstance(value, str):
        kb_value = float(value[:-3])
        if kb_value > 1024:
            mb_value = kb_value / 1024
            if mb_value > 1024:
                gb_value = mb_value / 1024
                if gb_value > 1024:
                    tb_value = gb_value / 1024
                    return '{:.2f} TB'.format(tb_value)
                else:
                    return '{:.2f} GB'.format(gb_value)
            else:
                return '{:.2f} MB'.format(mb_value)
    return value

def merge_dicts(d1, d2):
    """
    Merges two dictionaries.
    """
    return {**d1, **d2}


# add the custom filter to the Jinja2 environment
@app.template_filter()
def capitalize_first_letter(value):
    if value:
        return value[0].upper() + value[1:]
    return ''

app.jinja_env.filters['merge_dicts'] = merge_dicts
app.jinja_env.filters['filesize_fmt1'] = filesize_fmt1
app.jinja_env.filters['filesize_fmt'] = filesize_fmt
app.jinja_env.filters['add_space'] = add_space
app.jinja_env.filters['format_date2'] = format_date2
app.jinja_env.filters['format_date'] = format_date
app.jinja_env.filters['lstrip_zero'] = lstrip_zero
app.jinja_env.filters['gb_to_tb'] = gb_to_tb
app.jinja_env.filters['kb_to_tb'] = kb_to_tb

app.jinja_env.filters['bytes_to_gb'] = bytes_to_gb
app.jinja_env.filters['add_comma'] = add_comma

db = client.get_database('Opcenter')
dbs = client.get_database('MachinesDB')
session_dbssss = client.get_database('session_db')


#This for Authentication Users Information
auth = db.UsersData
#This for the Dashboard Data
usersTotal = dbs.usersTotal
colors = dbs.colors_set
CloudName = dbs.CloudName
LicenceData = dbs.LicenceData
AgentData = dbs.AgentVersion
blkuser = dbs.BlockUsers
LicenceDataAddil = dbs.LicenceDataAddi
spoc = dbs.spoc
MuxData = dbs.MuxData
MuxDatauserList = dbs.MuxDataUsers
sessions_collection = session_dbssss.sessions
deletedUs_ers = dbs.DeletedUsersList
soft_blk_usr = dbs.SoftBlockUsersList
dataprotectionList = dbs.dataprotection
loginHistory = db.loginHistory
bkplist = db.backupPolicyList


class SessionManager:
    def __init__(self, mongo_uri):
        self.client = MongoClient(mongo_uri)
        self.db = self.client["session_db"]
        self.collection = self.db["sessions"]

    def add_session(self, user_id, session_id):
        self.collection.insert_one({"user_id": user_id, "session_id": session_id})

    def get_user_sessions(self, user_id):
        return list(self.collection.find({"user_id": user_id}))

    def logout_user(self, user_id):
        print("The user id is : ")
        print(user_id)
        self.collection.delete_one({"user_id": user_id})
        print("Successfully Deleted")

    def check_user_logged_in(self, user_id, session_id):
        sessions = self.get_user_sessions(user_id)
        for session in sessions:
            if session["session_id"] != session_id:
                self.destroy_session(session["user_id"], session["session_id"])
                return True
        return False
    
    def destroy_session(self, user_id,session_id):
        self.collection.delete_one({"user_id": user_id,"session_id":session_id})




session_manager = SessionManager(app.config["MONGO_URI"])


# Session timeout code
def check_session_timeout():
    timeout = timedelta(minutes=10)
    while True:
        # Get the last access time of the session
        last_access_time = session.get('_accessed', None)
        if last_access_time is not None and datetime.now() - last_access_time > timeout:
            # If the session has timed out, log the user out and remove the session data
            user = auth.find_one({"username": session['username']})
            print(user['_id'])
            SessionManager.destroy_session(user['_id'])
            session.pop('username', None)
            session.clear()
        # Wait for some time before checking the session timeout again
        time.sleep(60)

def start_session_timeout_thread():
    timeout_thread = Thread(target=check_session_timeout)
    timeout_thread.start()


print("Successfully inserted")

bcrypt = Bcrypt(app)

@app.route('/logs')
def show_logs():
    with open('Opcenter.log', 'r') as f:
        logs = f.read().splitlines()
    
    table = '<table>'
    for log in logs:
        table += f'<tr><td>{log[:19]}</td><td>{log[31:]}</td></tr>'
    table += '</table>'
    
    return table



# from apps.authentication.routes import auth_blueprint
from Opcenter.apps.authentication.routes import auth_blueprint
from Opcenter.apps.main.routes import main
from Opcenter.apps.admin.routes import admin

app.register_blueprint(auth_blueprint)
app.register_blueprint(main)
app.register_blueprint(admin)