"""Exploit Development routes."""
import os
from flask import Blueprint, request, jsonify, render_template, current_app
from web.auth import login_required

exploit_dev_bp = Blueprint('exploit_dev', __name__, url_prefix='/exploit-dev')


def _get_dev():
    from modules.exploit_dev import get_exploit_dev
    return get_exploit_dev()


@exploit_dev_bp.route('/')
@login_required
def index():
    return render_template('exploit_dev.html')


@exploit_dev_bp.route('/shellcode', methods=['POST'])
@login_required
def shellcode():
    data = request.get_json(silent=True) or {}
    result = _get_dev().generate_shellcode(
        shell_type=data.get('type', 'execve'),
        arch=data.get('arch', 'x64'),
        host=data.get('host') or None,
        port=data.get('port') or None,
        platform=data.get('platform', 'linux'),
        staged=data.get('staged', False),
        output_format=data.get('output_format', 'hex'),
    )
    return jsonify(result)


@exploit_dev_bp.route('/shellcodes')
@login_required
def list_shellcodes():
    return jsonify({'shellcodes': _get_dev().list_shellcodes()})


@exploit_dev_bp.route('/encode', methods=['POST'])
@login_required
def encode():
    data = request.get_json(silent=True) or {}
    result = _get_dev().encode_payload(
        shellcode=data.get('shellcode', ''),
        encoder=data.get('encoder', 'xor'),
        key=data.get('key') or None,
        iterations=int(data.get('iterations', 1)),
    )
    return jsonify(result)


@exploit_dev_bp.route('/pattern/create', methods=['POST'])
@login_required
def pattern_create():
    data = request.get_json(silent=True) or {}
    length = int(data.get('length', 500))
    result = _get_dev().generate_pattern(length)
    return jsonify(result)


@exploit_dev_bp.route('/pattern/offset', methods=['POST'])
@login_required
def pattern_offset():
    data = request.get_json(silent=True) or {}
    result = _get_dev().find_pattern_offset(
        value=data.get('value', ''),
        length=int(data.get('length', 20000)),
    )
    return jsonify(result)


@exploit_dev_bp.route('/rop/gadgets', methods=['POST'])
@login_required
def rop_gadgets():
    data = request.get_json(silent=True) or {}
    binary_path = data.get('binary_path', '').strip()

    # Support file upload
    if not binary_path and request.content_type and 'multipart' in request.content_type:
        uploaded = request.files.get('binary')
        if uploaded:
            upload_dir = current_app.config.get('UPLOAD_FOLDER', '/tmp')
            binary_path = os.path.join(upload_dir, uploaded.filename)
            uploaded.save(binary_path)

    if not binary_path:
        return jsonify({'error': 'No binary path or file provided'}), 400

    gadget_type = data.get('gadget_type') or None
    if gadget_type == 'all':
        gadget_type = None

    result = _get_dev().find_rop_gadgets(binary_path, gadget_type)
    return jsonify(result)


@exploit_dev_bp.route('/rop/chain', methods=['POST'])
@login_required
def rop_chain():
    data = request.get_json(silent=True) or {}
    gadgets = data.get('gadgets', [])
    chain_spec = data.get('chain_spec', [])
    if not gadgets or not chain_spec:
        return jsonify({'error': 'Provide gadgets and chain_spec'}), 400
    result = _get_dev().build_rop_chain(gadgets, chain_spec)
    return jsonify(result)


@exploit_dev_bp.route('/format/offset', methods=['POST'])
@login_required
def format_offset():
    data = request.get_json(silent=True) or {}
    result = _get_dev().format_string_offset(
        binary_path=data.get('binary_path'),
        test_count=int(data.get('test_count', 20)),
    )
    return jsonify(result)


@exploit_dev_bp.route('/format/write', methods=['POST'])
@login_required
def format_write():
    data = request.get_json(silent=True) or {}
    address = data.get('address', '0')
    value = data.get('value', '0')
    offset = data.get('offset', 1)
    result = _get_dev().format_string_write(address, value, offset)
    return jsonify(result)


@exploit_dev_bp.route('/assemble', methods=['POST'])
@login_required
def assemble():
    data = request.get_json(silent=True) or {}
    result = _get_dev().assemble(
        code=data.get('code', ''),
        arch=data.get('arch', 'x64'),
    )
    return jsonify(result)


@exploit_dev_bp.route('/disassemble', methods=['POST'])
@login_required
def disassemble():
    data = request.get_json(silent=True) or {}
    result = _get_dev().disassemble(
        data=data.get('hex', ''),
        arch=data.get('arch', 'x64'),
        offset=int(data.get('offset', 0)),
    )
    return jsonify(result)
