from flask import Blueprint, render_template, request, session, redirect, url_for, jsonify
from functools import wraps
from werkzeug.security import check_password_hash
from app import mysql
import logging
import uuid
from app.config import Config

logger = logging.getLogger(__name__)

admin_bp = Blueprint('admin', __name__, url_prefix='/admin')


def admin_login_required(view_func):
    @wraps(view_func)
    def wrapped_view(*args, **kwargs):
        if 'admin_id' not in session:
            return redirect(url_for('admin.login'))
        return view_func(*args, **kwargs)

    return wrapped_view


@admin_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        if 'admin_id' in session:
            return redirect(url_for('admin.dashboard'))
        return render_template('admin/login.html')

    email = request.form.get('email')
    password = request.form.get('password')

    if not email or not password:
        return jsonify({"success": False, "error": "Email and password are required"}), 400

    cursor = mysql.connection.cursor()
    try:
        cursor.execute(
            "SELECT id, password, name FROM admins WHERE email = %s",
            (email,)
        )
        admin = cursor.fetchone()

        if not admin or not check_password_hash(admin[1], password):
            return jsonify({"success": False, "error": "Invalid credentials"}), 401

        session['admin_id'] = admin[0]
        session['admin_name'] = admin[2]

        cursor.execute(
            "UPDATE admins SET last_login_at = NOW() WHERE id = %s",
            (admin[0],)
        )
        mysql.connection.commit()

        return jsonify({"success": True})
    except Exception as exc:
        logger.error(f"Admin login error: {str(exc)}")
        return jsonify({"success": False, "error": "Unable to login"}), 500
    finally:
        cursor.close()


@admin_bp.route('/dashboard')
@admin_login_required
def dashboard():
    cursor = mysql.connection.cursor()
    try:
        cursor.execute("""
            SELECT
                COUNT(*) AS total_companies,
                SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending_companies,
                SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END) AS approved_companies,
                SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) AS rejected_companies
            FROM companies
        """)
        stats_row = cursor.fetchone()
        stats = {
            "total": stats_row[0] or 0,
            "pending": stats_row[1] or 0,
            "approved": stats_row[2] or 0,
            "rejected": stats_row[3] or 0,
        }

        cursor.execute("""
            SELECT
                id,
                name,
                email,
                status,
                is_verified,
                created_at
            FROM companies
            ORDER BY created_at DESC
            LIMIT 5
        """)
        latest_rows = cursor.fetchall()
        latest_companies = [
            {
                "id": row[0],
                "name": row[1],
                "email": row[2],
                "status": row[3],
                "is_verified": bool(row[4]),
                "created_at": row[5]
            }
            for row in latest_rows
        ]

        return render_template(
            'admin/dashboard.html',
            stats=stats,
            latest_companies=latest_companies
        )
    except Exception as exc:
        logger.error(f"Error loading admin dashboard: {str(exc)}")
        return render_template(
            'admin/dashboard.html',
            stats={"total": 0, "pending": 0, "approved": 0, "rejected": 0},
            latest_companies=[],
            error="Unable to load dashboard data."
        ), 500
    finally:
        cursor.close()


@admin_bp.route('/companies')
@admin_login_required
def companies():
    cursor = mysql.connection.cursor()
    try:
        cursor.execute("""
            SELECT
                id,
                name,
                email,
                status,
                is_verified,
                created_at,
                website,
                instructions,
                welcome_message
            FROM companies
            ORDER BY created_at DESC
        """)
        rows = cursor.fetchall()
        companies = [
            {
                "id": row[0],
                "name": row[1],
                "email": row[2],
                "status": row[3],
                "is_verified": bool(row[4]),
                "created_at": row[5],
                "website": row[6],
                "instructions": row[7],
                "welcome_message": row[8],
            }
            for row in rows
        ]

        return render_template('admin/companies.html', companies=companies)
    except Exception as exc:
        logger.error(f"Error loading companies page: {str(exc)}")
        return render_template('admin/companies.html', companies=[], error="Unable to load companies."), 500
    finally:
        cursor.close()


@admin_bp.route('/companies/<company_id>')
@admin_login_required
def company_detail(company_id):
    cursor = mysql.connection.cursor()
    try:
        cursor.execute("""
            SELECT
                id,
                name,
                email,
                status,
                is_verified,
                created_at,
                updated_at,
                website,
                instructions,
                welcome_message
            FROM companies
            WHERE id = %s
        """, (company_id,))
        row = cursor.fetchone()
        if not row:
            return redirect(url_for('admin.companies'))

        company = {
            "id": row[0],
            "name": row[1],
            "email": row[2],
            "status": row[3],
            "is_verified": bool(row[4]),
            "created_at": row[5],
            "updated_at": row[6],
            "website": row[7],
            "instructions": row[8],
            "welcome_message": row[9],
        }

        cursor.execute("""
            SELECT COUNT(*) FROM contacts WHERE company_id = %s
        """, (company_id,))
        contact_count = cursor.fetchone()[0]

        cursor.execute("""
            SELECT COUNT(*) FROM email_campaigns WHERE company_id = %s
        """, (company_id,))
        campaign_count = cursor.fetchone()[0]

        cursor.execute("""
            SELECT COUNT(*) FROM call_campaigns WHERE company_id = %s
        """, (company_id,))
        call_campaign_count = cursor.fetchone()[0]

        return render_template(
            'admin/company_detail.html',
            company=company,
            metrics={
                "contacts": contact_count,
                "email_campaigns": campaign_count,
                "call_campaigns": call_campaign_count,
            }
        )
    except Exception as exc:
        logger.error(f"Error loading company detail: {str(exc)}")
        return redirect(url_for('admin.companies'))
    finally:
        cursor.close()


@admin_bp.route('/logout')
def logout():
    session.pop('admin_id', None)
    session.pop('admin_name', None)
    return redirect(url_for('admin.login'))


@admin_bp.route('/companies/<company_id>/status', methods=['POST'])
@admin_login_required
def update_company_status(company_id):
    data = request.get_json(silent=True) or {}
    new_status = data.get('status')

    if new_status not in {'approved', 'pending', 'rejected'}:
        return jsonify({"success": False, "error": "Invalid status supplied."}), 400

    cursor = mysql.connection.cursor()
    try:
        cursor.execute("SELECT id FROM companies WHERE id = %s", (company_id,))
        if not cursor.fetchone():
            return jsonify({"success": False, "error": "Company not found."}), 404

        cursor.execute(
            """
            UPDATE companies
            SET status = %s,
                updated_at = NOW()
            WHERE id = %s
            """,
            (new_status, company_id)
        )
        mysql.connection.commit()
        return jsonify({"success": True})
    except Exception as exc:
        mysql.connection.rollback()
        logger.error(f"Error updating company status: {str(exc)}")
        return jsonify({"success": False, "error": "Failed to update company status."}), 500
    finally:
        cursor.close()


@admin_bp.route('/packages')
@admin_login_required
def packages():
    cursor = mysql.connection.cursor()
    try:
        cursor.execute("""
            SELECT id, title, description, no_of_contacts, no_of_mins, price, no_of_files
            FROM packages
            ORDER BY id ASC
        """)
        rows = cursor.fetchall()
        packages = [
            {
                "id": row[0],
                "title": row[1],
                "description": row[2],
                "no_of_contacts": row[3],
                "no_of_mins": row[4],
                "price": row[5],
                "no_of_files": row[6],
            }
            for row in rows
        ]
        return render_template('admin/packages.html', packages=packages, currency=Config.STRIPE_CURRENCY.upper())
    except Exception as exc:
        logger.error(f"Error loading packages page: {str(exc)}")
        return render_template('admin/packages.html', packages=[], error="Unable to load packages."), 500
    finally:
        cursor.close()


@admin_bp.route('/packages/<int:package_id>', methods=['POST'])
@admin_login_required
def update_package(package_id):
    data = request.get_json(silent=True) or {}
    title = (data.get('title') or '').strip()
    description = (data.get('description') or '').strip()
    contacts = data.get('no_of_contacts')
    minutes = data.get('no_of_mins')
    price = data.get('price')
    no_of_files = data.get('no_of_files')

    if not title:
        return jsonify({"success": False, "error": "Title is required."}), 400

    try:
        contacts_val = int(contacts) if contacts is not None else 0
        minutes_val = int(minutes) if minutes is not None else 0
        price_val = float(price) if price is not None else 0.0
        no_of_files_val = int(no_of_files) if no_of_files is not None else 0
    except (TypeError, ValueError):
        return jsonify({"success": False, "error": "Contacts, minutes and price must be numbers."}), 400

    cursor = mysql.connection.cursor()
    try:
        cursor.execute("SELECT id FROM packages WHERE id = %s", (package_id,))
        if not cursor.fetchone():
            return jsonify({"success": False, "error": "Package not found."}), 404

        cursor.execute(
            """
            UPDATE packages
            SET title = %s,
                description = %s,
                no_of_contacts = %s,
                no_of_mins = %s,
                price = %s,
                no_of_files = %s,
                updated_at = NOW()
            WHERE id = %s
            """,
            (title, description, contacts_val, minutes_val, price_val, no_of_files_val, package_id)
        )
        mysql.connection.commit()
        return jsonify({
            "success": True,
            "package": {
                "id": package_id,
                "title": title,
                "description": description,
                "no_of_contacts": contacts_val,
                "no_of_mins": minutes_val,
                "price": price_val,
                "no_of_files": no_of_files_val,
            }
        })
    except Exception as exc:
        mysql.connection.rollback()
        logger.error(f"Error updating package {package_id}: {str(exc)}")
        return jsonify({"success": False, "error": "Failed to update package."}), 500
    finally:
        cursor.close()


@admin_bp.route('/billing')
@admin_login_required
def billing():
    cursor = mysql.connection.cursor()
    try:
        cursor.execute("""
            SELECT
                cpp.id,
                c.name,
                c.email,
                p.title,
                cpp.amount,
                cpp.currency,
                cpp.status,
                cpp.started_at,
                cpp.expires_at,
                cpp.created_at,
                cpp.completed_at
            FROM company_package_payments cpp
            JOIN companies c ON cpp.company_id = c.id
            JOIN packages p ON cpp.package_id = p.id
            ORDER BY cpp.created_at DESC
        """)
        payments = cursor.fetchall()
        return render_template('admin/billing.html', payments=payments)
    except Exception as exc:
        logger.error(f"Error loading billing page: {str(exc)}")
        return render_template('admin/billing.html', payments=[], error="Unable to load billing records."), 500
    finally:
        cursor.close()


@admin_bp.route('/settings', methods=['GET', 'POST'])
@admin_login_required
def settings():
    cursor = mysql.connection.cursor()
    success_message = None
    error_message = None
    current_settings = {
        "file_size_limit": "",
        "mail_mailer": "",
        "mail_host": "",
        "mail_port": "",
        "mail_username": "",
        "mail_password": "",
        "mail_encryption": "",
        "mail_from_address": "",
        "mail_from_name": "",
        "admin_email": "",
    }
    try:
        if request.method == 'POST':
            file_size_limit = (request.form.get('file_size_limit') or '').strip()
            mail_mailer = (request.form.get('mail_mailer') or '').strip()
            mail_host = (request.form.get('mail_host') or '').strip()
            mail_port_raw = (request.form.get('mail_port') or '').strip()
            mail_username = (request.form.get('mail_username') or '').strip()
            mail_password = (request.form.get('mail_password') or '').strip()
            mail_encryption = (request.form.get('mail_encryption') or '').strip()
            mail_from_address = (request.form.get('mail_from_address') or '').strip()
            mail_from_name = (request.form.get('mail_from_name') or '').strip()
            admin_email = (request.form.get('admin_email') or '').strip()
            current_settings.update({
                "file_size_limit": file_size_limit,
                "mail_mailer": mail_mailer,
                "mail_host": mail_host,
                "mail_port": mail_port_raw,
                "mail_username": mail_username,
                "mail_password": mail_password,
                "mail_encryption": mail_encryption,
                "mail_from_address": mail_from_address,
                "mail_from_name": mail_from_name,
                "admin_email": admin_email,
            })

            if not file_size_limit:
                error_message = "File size limit is required."
            else:
                try:
                    file_size_value = int(file_size_limit)
                    if file_size_value <= 0:
                        raise ValueError
                    mail_port_value = None
                    if mail_port_raw:
                        mail_port_value = int(mail_port_raw)
                        if mail_port_value <= 0:
                            raise ValueError
                    cursor.execute("""
                        INSERT INTO admin_settings (
                            id,
                            file_size_limit,
                            mail_mailer,
                            mail_host,
                            mail_port,
                            mail_username,
                            mail_password,
                            mail_encryption,
                            mail_from_address,
                            mail_from_name,
                            admin_email
                        )
                        VALUES (
                            1,
                            %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
                        )
                        ON DUPLICATE KEY UPDATE
                            file_size_limit = VALUES(file_size_limit),
                            mail_mailer = VALUES(mail_mailer),
                            mail_host = VALUES(mail_host),
                            mail_port = VALUES(mail_port),
                            mail_username = VALUES(mail_username),
                            mail_password = VALUES(mail_password),
                            mail_encryption = VALUES(mail_encryption),
                            mail_from_address = VALUES(mail_from_address),
                            mail_from_name = VALUES(mail_from_name),
                            admin_email = VALUES(admin_email),
                            updated_at = NOW()
                    """, (
                        file_size_value,
                        mail_mailer or None,
                        mail_host or None,
                        mail_port_value,
                        mail_username or None,
                        mail_password or None,
                        mail_encryption or None,
                        mail_from_address or None,
                        mail_from_name or None,
                        admin_email or None,
                    ))
                    mysql.connection.commit()
                    success_message = "Settings updated successfully."
                except ValueError:
                    error_message = "Please enter valid numeric values for file size limit and port."
        if not error_message:
            cursor.execute("""
                SELECT
                    file_size_limit,
                    mail_mailer,
                    mail_host,
                    mail_port,
                    mail_username,
                    mail_password,
                    mail_encryption,
                    mail_from_address,
                    mail_from_name,
                    admin_email
                FROM admin_settings
                WHERE id = 1
            """)
        row = cursor.fetchone()
        if row:
            current_settings = {
                "file_size_limit": row[0] if row[0] is not None else "",
                "mail_mailer": row[1] if row[1] is not None else "",
                "mail_host": row[2] if row[2] is not None else "",
                "mail_port": str(row[3]) if row[3] is not None else "",
                "mail_username": row[4] if row[4] is not None else "",
                "mail_password": row[5] if row[5] is not None else "",
                "mail_encryption": row[6] if row[6] is not None else "",
                "mail_from_address": row[7] if row[7] is not None else "",
                "mail_from_name": row[8] if row[8] is not None else "",
                "admin_email": row[9] if row[9] is not None else "",
            }
    except Exception as exc:
        mysql.connection.rollback()
        logger.error(f"Error updating admin settings: {str(exc)}")
        if not error_message:
            error_message = "Unable to save settings at the moment."
    finally:
        cursor.close()
    return render_template(
        'admin/settings.html',
        file_size_limit=current_settings.get("file_size_limit", ""),
        settings=current_settings,
        success_message=success_message,
        error_message=error_message
    )


@admin_bp.route('/support-tickets')
@admin_login_required
def support_tickets():
    cursor = mysql.connection.cursor()
    
    # Fetch all tickets with company info and unread count
    cursor.execute("""
        SELECT 
            st.id, 
            st.title, 
            st.reason, 
            st.priority, 
            st.status, 
            st.created_at, 
            st.updated_at,
            c.name AS company_name,
            c.email AS company_email,
            COALESCE((
                SELECT COUNT(*) 
                FROM support_ticket_messages stm
                LEFT JOIN support_ticket_read_status str ON str.ticket_id = stm.ticket_id 
                    AND str.reader_type = 'admin' 
                    AND str.reader_id = %s
                WHERE stm.ticket_id = st.id 
                    AND stm.sender_type = 'company'
                    AND (str.last_read_at IS NULL OR stm.created_at > str.last_read_at)
            ), 0) AS unread_count
        FROM support_tickets st
        JOIN companies c ON st.company_id = c.id
        ORDER BY st.created_at DESC
    """, (session['admin_id'],))
    
    tickets = cursor.fetchall()
    cursor.close()
    
    return render_template('admin/support_tickets.html', tickets=tickets)

@admin_bp.route('/support-tickets/<ticket_id>')
@admin_login_required
def view_support_ticket(ticket_id):
    import uuid
    cursor = mysql.connection.cursor()
    
    # Fetch ticket with company info
    cursor.execute("""
        SELECT 
            st.id, 
            st.title, 
            st.reason, 
            st.priority, 
            st.status, 
            st.created_at, 
            st.updated_at,
            c.name AS company_name,
            c.email AS company_email,
            c.id AS company_id
        FROM support_tickets st
        JOIN companies c ON st.company_id = c.id
        WHERE st.id = %s
    """, (ticket_id,))
    
    ticket = cursor.fetchone()
    
    if not ticket:
        cursor.close()
        return redirect(url_for('admin.support_tickets'))
    
    # Mark messages as read for admin
    read_status_id = str(uuid.uuid4())
    cursor.execute("""
        INSERT INTO support_ticket_read_status (id, ticket_id, reader_type, reader_id, last_read_at)
        VALUES (%s, %s, 'admin', %s, NOW())
        ON DUPLICATE KEY UPDATE last_read_at = NOW(), updated_at = NOW()
    """, (read_status_id, ticket_id, session['admin_id']))
    mysql.connection.commit()
    
    # Fetch messages
    cursor.execute("""
        SELECT id, sender_type, sender_id, message, created_at
        FROM support_ticket_messages
        WHERE ticket_id = %s
        ORDER BY created_at ASC
    """, (ticket_id,))
    
    messages = cursor.fetchall()
    
    # Get admin name
    admin_name = session.get('admin_name', 'Admin')
    
    cursor.close()
    
    return render_template('admin/support_ticket_detail.html', 
                         ticket=ticket, 
                         messages=messages,
                         admin_name=admin_name)

@admin_bp.route('/support-tickets/<ticket_id>/message', methods=['POST'])
@admin_login_required
def add_ticket_message(ticket_id):
    try:
        data = request.json
        message = data.get('message', '').strip()
        
        if not message:
            return jsonify({
                "success": False,
                "error": "Message is required"
            }), 400
        
        cursor = mysql.connection.cursor()
        
        # Verify ticket exists and is not closed
        cursor.execute("SELECT id, status FROM support_tickets WHERE id = %s", (ticket_id,))
        ticket = cursor.fetchone()
        if not ticket:
            cursor.close()
            return jsonify({
                "success": False,
                "error": "Ticket not found"
            }), 404
        
        if ticket[1] == 'closed':
            cursor.close()
            return jsonify({
                "success": False,
                "error": "Cannot send messages to a closed ticket"
            }), 400
        
        message_id = str(uuid.uuid4())
        cursor.execute("""
            INSERT INTO support_ticket_messages (id, ticket_id, sender_type, sender_id, message)
            VALUES (%s, %s, 'admin', %s, %s)
        """, (message_id, ticket_id, session['admin_id'], message))
        
        # Update ticket updated_at
        cursor.execute("""
            UPDATE support_tickets
            SET updated_at = NOW()
            WHERE id = %s
        """, (ticket_id,))
        
        mysql.connection.commit()
        cursor.close()
        
        return jsonify({
            "success": True,
            "message": "Message sent successfully",
            "message_id": message_id
        })
    except Exception as e:
        logger.error(f"Error adding ticket message: {str(e)}")
        return jsonify({"success": False, "error": str(e)}), 500

@admin_bp.route('/support-tickets/<ticket_id>/status', methods=['POST'])
@admin_login_required
def update_ticket_status(ticket_id):
    try:
        data = request.json
        status = data.get('status', '').strip()
        
        if status not in ['open', 'in_progress', 'resolved', 'closed']:
            return jsonify({
                "success": False,
                "error": "Invalid status"
            }), 400
        
        cursor = mysql.connection.cursor()
        cursor.execute("""
            UPDATE support_tickets
            SET status = %s, updated_at = NOW()
            WHERE id = %s
        """, (status, ticket_id))
        
        mysql.connection.commit()
        cursor.close()
        
        return jsonify({
            "success": True,
            "message": "Status updated successfully"
        })
    except Exception as e:
        logger.error(f"Error updating ticket status: {str(e)}")
        return jsonify({"success": False, "error": str(e)}), 500

@admin_bp.context_processor
def inject_admin():
    if 'admin_id' in session:
        cursor = mysql.connection.cursor()
        try:
            cursor.execute(
                "SELECT id, name, email FROM admins WHERE id = %s",
                (session['admin_id'],)
            )
            admin = cursor.fetchone()
            if admin:
                admin_data = {
                    "id": admin[0],
                    "name": admin[1],
                    "email": admin[2]
                }
            else:
                admin_data = None
            return {'admin_user': admin_data}
        except Exception:
            return {'admin_user': None}
        finally:
            cursor.close()
    return {'admin_user': None}

