from flask import Flask, jsonify, render_template, request, redirect, url_for, session, make_response
import psycopg2
from psycopg2.extras import RealDictCursor
import json
import traceback
from functools import wraps
from middleware import NoCacheMiddleware  # Import the middleware


app = Flask(__name__)

app.wsgi_app = NoCacheMiddleware(app.wsgi_app)


MODE = 'production'

DB_CONFIG = {
    'production': {
        "user": "admin_readonly_user",
        "password": "6pSm01RpD93fYXe",
        "dbname": "signapp1238",
        "host": "3.20.38.39",
    },
    'staging': {
        "user": "postgres",
        "password": "ZuVn6XS7vwQwPnFu",
        "dbname": "signapp1238",
        "host": "localhost",
    },
    'local': {
        "user": "root",
        "password": "password",
        "dbname": "signpe_db",
        "host": "localhost",
    }
}


# GETTING_MODE

config = DB_CONFIG[MODE]

live_user = config['user']
live_user_pwd = config['password']
live_database_name = config['dbname']
live_host = config['host']
# Create your views here.

conn = psycopg2.connect(
    dbname=live_database_name,
    user=live_user,
    password=live_user_pwd,
    host=live_host,
    port="5432"
)

app.secret_key = 'f95030c05f12439be285dc01f45813dc89ccc93ce2f8360d'

# -----------------Check Functions-------------------
def check_criteria(element, email):
    return element['assignedTo'] == email and element['type'] == "Signature" and element['imageBase64'] is not None


@app.route('/get_count/', methods=['GET'])
def get_count():
    if request.method == 'GET':
        try:
            with conn.cursor(cursor_factory=RealDictCursor) as cursor:
                cursor.execute(""" SELECT id FROM public."user" """)
                user_data = cursor.fetchall()  
                count_user = len(user_data)
                cursor.execute(""" SELECT id FROM public."document" """)
                document_data = cursor.fetchall()
                count_documents = len(document_data)

                count_signatureds = count_signatured()
                cursor.execute(""" SELECT id FROM public."user" u WHERE NOT u."totalCreatedDocuments" = 0 """)
                totaluserDoclist = cursor.fetchall()
                count_totaluserDoc = len(totaluserDoclist)

                context = {
                    'count_user':count_user,
                    'count_documents':count_documents,
                    'count_signatureds':count_signatureds,
                    'count_totaluserDoc':count_totaluserDoc
                }
                return jsonify(context)
            
        except Exception as e:
            excp_mail = traceback.format_exc()
            print(excp_mail)
            return jsonify(f"Database error: {e}")    
    else:
        pass
    return jsonify("Invalid request method.", status=405)    
                                        

# ----------------remove----dublipcate---users----------
def user_id_remover(user_id, email, doc, true_count, user_data_list):
    exists = any(filter(lambda item: item['id'] == user_id, user_data_list))
    if not exists:
        user_data_list.append({
            'id': user_id,
            'email': email,
            'total_documents': doc.get('totalCreatedDocuments', 0),
            'signed_documents': true_count,
        })

def count_signatured():
    with conn.cursor(cursor_factory=RealDictCursor) as cursor:
        cursor.execute("""
           SELECT u.id, u.email, d.annotation
            FROM "user" u
            LEFT JOIN "transaction" t ON u.id = t."createdByUserId"
            LEFT JOIN "document" d ON t.id = d."transactionId"
            WHERE d.annotation IS NOT NULL
            ORDER BY u.id ASC;
        """)
        documents = cursor.fetchall()
        user_data = {}
        true_count = 0
        user_id = -1
        for doc in documents:
            email = doc.get('email')
            user_id = doc.get('id')
            annotation_str = doc.get("annotation")
            if annotation_str:
                my_json = json.loads(annotation_str)
                filtered_data = []
                for v in my_json.values():
                    filter_item = list(filter(lambda element: check_criteria(element, email), v))
                    if filter_item:
                        filtered_data = filter_item
                if len(filtered_data) >= 1:
                    true_count += 1
                    user_data[user_id] = true_count
        return true_count

# -----------------Login Routes-------------------

@app.route('/login/', methods=['GET', 'POST'])
def login():
    try:
        if request.method == 'POST':
            email = request.form.get('email')
            password = request.form.get('password')

            STATIC_EMAIL = 'admin@gmail.com'
            STATIC_PASSWORD = 'admin@123'

            if email == STATIC_EMAIL and password == STATIC_PASSWORD:
                response = make_response(redirect(url_for('get_user')))
                response.set_cookie('user_email', email)
                return response
            else:
                return render_template('sign-in.html', message="Invalid email or password")
        return render_template('sign-in.html')
    except Exception as e:
        traceback.print_exc()
        return "An error occurred", 500

@app.route('/logout/')
def logout():
    response = redirect(url_for('login'))
    response.delete_cookie('user_email')
    return response

# --------------Authentication Decorator--------------

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not request.cookies.get('user_email'):
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated_function

# -----------------Homepage Route-------------------
@app.route('/',methods=['GET'])
@login_required
def indexpage():
    try:
        data = {
            "Users": 12,
            "weekly_active": 12,
            "yearly_active": 12
        }
        return render_template("index.html", data=data)
    except Exception as e:
        # traceback.print_exc()
        return "An error occurred", 500

# -----------------Fetching User Data-------------------
@app.route('/get_user/')
@login_required
def get_user():
    try:
        return render_template('user-list.html')
    except Exception as e:
        traceback.print_exc()
        return "Database error", 500


def checkCriteria(element, email):
    return element['assignedTo'] == email and element['type'] == "Signature" and element['imageBase64'] is not None

@app.route('/fetch_user_data/', methods=['GET'])
def fetch_user_data():
    if request.method == 'GET':
        try:
            draw = int(request.args.get('draw', 1))
            start = int(request.args.get('start', 0))
            length = int(request.args.get('length', 100))
            search_value = request.args.get('search[value]', '')

            search_filter = f"%{search_value}%" if search_value else '%'
            with conn.cursor(cursor_factory=RealDictCursor) as cursor:
        
                count_query = """
                    SELECT COUNT(*) AS count
                    FROM "user" WHERE email NOT LIKE '%%@yopmail.com'
                """

                cursor.execute(count_query, [search_filter])

                total_count = cursor.fetchone()['count']

                data_query = ""
                if search_value:
                    data_query = f" AND us.email ILIKE %s"

                data_query += "ORDER BY us.id LIMIT %s OFFSET %s"

                # Main query
                query = f"""
                SELECT
                    u."id",
                    u."email",
                    u."totalCreatedDocuments",
                    d."annotation",
                    d."transactionId"
                FROM    
                    "user" u
                LEFT JOIN "transaction" t ON u.id = t."createdByUserId"
                LEFT JOIN "document" d ON t.id = d."transactionId"
                WHERE u."id" IN (
                    SELECT us.id FROM "user" us 
                    WHERE us.email NOT LIKE '%%@yopmail.com' {data_query}
                )
                ORDER BY u."id" ASC;
                """

                params = []
                if search_value:
                    params.append(f"%{search_value}%")
                params.extend([length, start])

                cursor.execute(query, params)

                documents = cursor.fetchall()
                user_data = {}
                true_count =0
                false_count = 0
                user_id = -1
                user_data_list = []
                for doc in documents:
                    if user_id != doc.get('id') :
                        true_count = 0
                        
                    email = doc.get('email')
                    user_id = doc.get('id')
                    annotation_str = doc.get("annotation")
                    if annotation_str:
                        myJson = json.loads(annotation_str)
                        filteredData = []
                        for v in myJson.values():
                            filterItem = list(filter(lambda element: checkCriteria(element,email),v))
                            if filterItem != []:
                                filteredData = filterItem

                        if (len(filteredData) >= 1):
                            true_count += 1
                            user_data[user_id] = true_count
                            index = next((i for i, item in enumerate(user_data_list) if item['id'] == user_id), None)
                            if index is not None :
                                user_data_list[index]['signed_documents'] = true_count
                            else :
                                user_data_list.append({
                                    'id':user_id,
                                    'email':email,
                                    'total_documents': doc.get('totalCreatedDocuments', 0),
                                    'signed_documents': true_count
                                })

                        else:
                            user_id_remover(user_id, email, doc, true_count, user_data_list)
                    else:
                       user_id_remover(user_id, email, doc, true_count, user_data_list)
                response_data = {
                    'draw': draw,
                    'recordsTotal': total_count,
                    'recordsFiltered': total_count,
                    'data': user_data_list
                }

                return jsonify(response_data)
        except Exception as e:
            excp_mail = traceback.format_exc()
            return jsonify(f"Database error: {excp_mail}")
    return jsonify("Invalid request method.", status=405)

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=11188,debug=True)
