import logging

from flask import render_template, Blueprint, request, redirect, url_for, flash, session
from flask_login import login_required, current_user
from forms import FormVirtualMachine, UpdateVmInfo
from db_manager import db, VirtualMachine, Actions, get_user_by_username, get_vm_by_vms
from dotenv import load_dotenv
from datetime import datetime
from pyVim import connect
from sqlalchemy import func
import ssl
import os

vm_blueprint = Blueprint('vm', __name__)

load_dotenv()

hypervisors = {
    "5.9.87.101": {"user": os.getenv("HYPER1_USER"), "password": os.getenv("HYPER1_PASS"),
                   "host": os.getenv("HYPER1_HOST")},
    "135.181.138.180": {"user": os.getenv("HYPER2_USER"), "password": os.getenv("HYPER2_PASS"),
                        "host": os.getenv("HYPER2_HOST")},
    "136.243.43.245": {"user": os.getenv("HYPER3_USER"), "password": os.getenv("HYPER3_PASS"),
                       "host": os.getenv("HYPER3_HOST")},
    "65.108.193.220": {"user": os.getenv("HYPER4_USER"), "password": os.getenv("HYPER4_PASS"),
                       "host": os.getenv("HYPER4_HOST")}
}


@vm_blueprint.route('/dashboard', methods=['GET', 'POST'])
@login_required
def dashboard():
    virtual_machines = VirtualMachine.query.all()

    return render_template('dashboard.html', virtual_machines=virtual_machines)


@vm_blueprint.route('/vms', methods=['GET', 'POST'])
@login_required
def vms():
    virtual_machines = VirtualMachine.query.all()
    return render_template('vms.html', virtual_machines=virtual_machines)


@vm_blueprint.route('/manage', methods=['GET', 'POST'])
@login_required
def manage():
    virtual_machines = VirtualMachine.query.all()
    return render_template('manage.html', virtual_machines=virtual_machines)


@vm_blueprint.route('/add', methods=['GET', 'POST'])
@login_required
def add_virtual_machine():
    form = FormVirtualMachine(request.form)
    if request.method == 'POST':
        new_vm = VirtualMachine(hyper=form.hyper.data, id_vm=form.id_vm.data, name=form.name.data,
                                os=form.os.data, memory=form.memory.data, cpu=form.cpu.data,
                                technical=form.technical.data, status="Свободно")
        db.session.add(new_vm)
        db.session.commit()

        return redirect(url_for('vm.dashboard'))
    return render_template('add.html', form=form)


@vm_blueprint.route('/delete/<int:id>', methods=['GET', 'POST'])
@login_required
def delete_virtual_machine(id):
    vm_to_delete = VirtualMachine.query.get_or_404(id)
    new_action = Actions(user_id=get_user_by_username(current_user.username).id,
                         action_type='del_vm',
                         vm=get_vm_by_vms(vm_to_delete.hyper, vm_to_delete.name).id)
    db.session.add(new_action)
    db.session.commit()
    db.session.delete(vm_to_delete)
    db.session.commit()
    flash(f'Виртуальная машина {vm_to_delete.name} удалена!', 'success')
    return redirect(url_for('vm.vms'))


@vm_blueprint.route('/edit/<int:id>', methods=['GET', 'POST'])
@login_required
def edit_virtual_machine(id):
    vm_to_edit = VirtualMachine.query.get_or_404(id)
    if request.method == 'POST':
        vm_to_edit.hyper = request.form['hyper']
        vm_to_edit.ip_addres = request.form['ip_addres']
        vm_to_edit.name = request.form['name']
        vm_to_edit.appointment = request.form['appointment']
        vm_to_edit.os = request.form['os']
        vm_to_edit.memory = request.form['memory']
        vm_to_edit.cpu = request.form['cpu']
        vm_to_edit.technical = request.form.get('technical', False) == 'on'
        new_action = Actions(user_id=get_user_by_username(current_user.username).id,
                             action_type='edit_vm',
                             vm=get_vm_by_vms(vm_to_edit.hyper, vm_to_edit.name).id)
        db.session.add(new_action)
        db.session.commit()
        flash(f'Виртуальная машина {vm_to_edit.name} отредактирована!', 'success')
        return redirect(url_for('vm.vms'))
    return render_template('edit.html', virtual_machine=vm_to_edit)


@vm_blueprint.route('/occupy/<int:id>', methods=['GET', 'POST'])
@login_required
def occupy_vm(id):
    vm = VirtualMachine.query.get_or_404(id)
    if request.method == 'POST':
        vm.status = 'Занято'
        vm.task = request.form['task']
        vm.busy_date = datetime.now().strftime('%d.%m.%Y %H:%M')
        vm.who_borrowed = current_user.name
        vm.who_borrowed_username = current_user.username
        new_action = Actions(user_id=get_user_by_username(current_user.username).id,
                             action_type='occupy_vm',
                             vm=get_vm_by_vms(vm.hyper, vm.name).id)
        db.session.add(new_action)
        db.session.commit()
        return redirect(url_for('vm.dashboard'))
    return render_template('index.html', virtual_machines=VirtualMachine.query.all())


@vm_blueprint.route('/release/<int:id>', methods=['GET', 'POST'])
@login_required
def release_vm(id):
    vm = VirtualMachine.query.get_or_404(id)
    if request.method == 'POST':
        vm.status = 'Свободно'
        vm.task = 'Свободно'
        vm.busy_date = 'Свободно'
        vm.who_borrowed = 'Свободно'
        vm.who_borrowed_username = 'Свободно'
        new_action = Actions(user_id=get_user_by_username(current_user.username).id,
                             action_type='release_vm',
                             vm=get_vm_by_vms(vm.hyper, vm.name).id)
        db.session.add(new_action)
        db.session.commit()
        return redirect(url_for('vm.dashboard'))
    return redirect(url_for('index'))


def disable_ssl_verification():
    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)
    ssl_context.verify_mode = ssl.CERT_NONE
    return ssl_context


def find_vm_by_name(content, vm_name):
    vm = None
    for child in content.rootFolder.childEntity:
        if hasattr(child, 'vmFolder'):
            vm_folder = child.vmFolder
            vm_list = vm_folder.childEntity
            for vm_obj in vm_list:
                if vm_obj.name == vm_name:
                    vm = vm_obj
                    break
            if vm:
                break
    return vm


def read_content(hyper):
    if hyper in hypervisors:
        user = hypervisors[hyper]["user"]
        password = hypervisors[hyper]["password"]
        host = hypervisors[hyper]["host"]
    else:
        flash(f'Узел {hyper} не найден', 'danger')
        return redirect(url_for('vm.manage'))

    service_instance = connect.SmartConnect(
        host=host,
        user=user,
        pwd=password,
        sslContext=disable_ssl_verification()
    )
    content = service_instance.RetrieveContent()
    return content


@vm_blueprint.route('/start/<string:name>/<string:hyper>', methods=['GET', 'POST'])
@login_required
def start_virtual_machine(name, hyper):
    vm = find_vm_by_name(read_content(hyper), name)
    try:
        if vm:
            vm.PowerOnVM_Task()
            new_action = Actions(user_id=get_user_by_username(current_user.username).id,
                                 action_type='start_vm',
                                 vm=get_vm_by_vms(hyper, name).id)
            db.session.add(new_action)
            db.session.commit()
            flash(f'Запущена виртуальная машина: {name} на гипервизоре {hyper}.', 'success')
            return redirect(url_for('vm.manage'))
        else:
            flash(f'Ошибка запуска виртуальной машины: {name} на гипервизоре {hyper}.', 'danger')
            return redirect(url_for('vm.manage'))
    except Exception as e:
        flash(f'При выполнении операции запуска возникла ошибка {e}', 'danger')
        return redirect(url_for('vm.manage'))


@vm_blueprint.route('/stop/<string:name>/<string:hyper>', methods=['GET', 'POST'])
@login_required
def stop_virtual_machine(name, hyper):
    vm = find_vm_by_name(read_content(hyper), name)
    try:
        if vm:
            vm.PowerOffVM_Task()
            new_action = Actions(user_id=get_user_by_username(current_user.username).id,
                                 action_type='stop_vm',
                                 vm=get_vm_by_vms(hyper, name).id)
            db.session.add(new_action)
            db.session.commit()
            flash(f'Остановлена виртуальная машина: {name} на гипервизоре {hyper}.', 'success')
            return redirect(url_for('vm.manage'))
        else:
            flash(f'Ошибка остановки виртуальной машины: {name} на гипервизоре {hyper}.', 'danger')
            return redirect(url_for('vm.manage'))
    except Exception as e:
        flash(f'При выполнении операции остановки возникла ошибка {e}', 'danger')
        return redirect(url_for('vm.manage'))


@vm_blueprint.route('/restart/<string:name>/<string:hyper>', methods=['GET', 'POST'])
@login_required
def restart_virtual_machine(name, hyper):
    vm = find_vm_by_name(read_content(hyper), name)

    try:
        if vm:
            vm.ResetVM_Task()
            new_action = Actions(user_id=get_user_by_username(current_user.username).id,
                                 action_type='restart_vm',
                                 vm=get_vm_by_vms(hyper, name).id)
            db.session.add(new_action)
            db.session.commit()
            flash(f'Перезагружена виртуальная машина: {name} на гипервизоре {hyper}.', 'success')
            return redirect(url_for('vm.manage'))
        else:
            flash(f'Ошибка перезагрузки виртуальной машины: {name} на гипервизоре {hyper}.', 'danger')
            return redirect(url_for('vm.manage'))
    except Exception as e:
        flash(f'При выполнении операции перезагрузки возникла ошибка {e}', 'danger')
        return redirect(url_for('vm.manage'))


@vm_blueprint.route('/vm_info/<string:name>/<string:hyper>', methods=['GET', 'POST'])
@login_required
def vm_info(name, hyper):
    all_data_vm = VirtualMachine.query.filter_by(hyper=hyper, name=name).first()

    if not all_data_vm:
        flash('Виртуальная машина не найдена.', 'danger')
        return redirect(url_for('vm.dashboard'))

    form = UpdateVmInfo(request.form)

    if request.method == 'POST' and form.validate():
        all_data_vm.information = form.information.data
        db.session.commit()
        flash('Комментарий к виртуальной машине успешно обновлена.', 'success')
        return redirect(url_for('vm.dashboard'))
    elif request.method == 'POST':
        flash('Ошибка при обновлении комментария к виртуальной машине.', 'danger')

    return render_template('vm_info.html', form=form, all_data_vm=all_data_vm, information=all_data_vm.information)


@vm_blueprint.route('/statistics/', methods=['GET', 'POST'])
@login_required
def vm_statistics():
    try:
        most_used_vm = db.session.query(Actions.vm, func.count(Actions.vm).label('vm_count')).group_by(Actions.vm).order_by(
            func.count(Actions.vm).desc()).first()

        action_counts = db.session.query(Actions.action_type,
                                         func.count(Actions.action_type).label('action_count')).group_by(
            Actions.action_type).order_by(func.count(Actions.action_type).desc()).all()

        data_vm = VirtualMachine.query.filter_by(id=most_used_vm[0]).first()

        return render_template('statistics.html', data_vm=data_vm, action_counts=action_counts)

    except Exception as e:
        logging.error(f"Ошибка отображения статистики {e}")
        return render_template('statistics.html', data_vm=None, action_counts=None)