"""iPhone Exploitation routes - Local USB device access via libimobiledevice."""

import os
from flask import Blueprint, render_template, request, jsonify
from web.auth import login_required

iphone_exploit_bp = Blueprint('iphone_exploit', __name__, url_prefix='/iphone-exploit')


def _get_mgr():
    from core.iphone_exploit import get_iphone_manager
    return get_iphone_manager()


def _get_udid():
    data = request.get_json(silent=True) or {}
    udid = data.get('udid', '').strip()
    if not udid:
        return None, jsonify({'error': 'No UDID provided'})
    return udid, None


@iphone_exploit_bp.route('/')
@login_required
def index():
    mgr = _get_mgr()
    status = mgr.get_status()
    return render_template('iphone_exploit.html', status=status)


# ── Device Management ────────────────────────────────────────────

@iphone_exploit_bp.route('/devices', methods=['POST'])
@login_required
def list_devices():
    return jsonify({'devices': _get_mgr().list_devices()})


@iphone_exploit_bp.route('/device-info', methods=['POST'])
@login_required
def device_info():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().device_info(udid))


@iphone_exploit_bp.route('/fingerprint', methods=['POST'])
@login_required
def fingerprint():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().full_fingerprint(udid))


@iphone_exploit_bp.route('/pair', methods=['POST'])
@login_required
def pair():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().pair_device(udid))


@iphone_exploit_bp.route('/unpair', methods=['POST'])
@login_required
def unpair():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().unpair_device(udid))


@iphone_exploit_bp.route('/validate-pair', methods=['POST'])
@login_required
def validate_pair():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().validate_pair(udid))


@iphone_exploit_bp.route('/get-name', methods=['POST'])
@login_required
def get_name():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().get_name(udid))


@iphone_exploit_bp.route('/set-name', methods=['POST'])
@login_required
def set_name():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    name = data.get('name', '').strip()
    if not name:
        return jsonify({'error': 'No name provided'})
    return jsonify(_get_mgr().set_name(udid, name))


@iphone_exploit_bp.route('/restart', methods=['POST'])
@login_required
def restart():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().restart_device(udid))


@iphone_exploit_bp.route('/shutdown', methods=['POST'])
@login_required
def shutdown():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().shutdown_device(udid))


@iphone_exploit_bp.route('/sleep', methods=['POST'])
@login_required
def sleep_dev():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().sleep_device(udid))


# ── Capture ──────────────────────────────────────────────────────

@iphone_exploit_bp.route('/screenshot', methods=['POST'])
@login_required
def screenshot():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().screenshot(udid))


@iphone_exploit_bp.route('/syslog', methods=['POST'])
@login_required
def syslog():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    duration = int(data.get('duration', 5))
    return jsonify(_get_mgr().syslog_dump(udid, duration=duration))


@iphone_exploit_bp.route('/syslog-grep', methods=['POST'])
@login_required
def syslog_grep():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    pattern = data.get('pattern', 'password|token|key|secret')
    duration = int(data.get('duration', 5))
    return jsonify(_get_mgr().syslog_grep(udid, pattern, duration=duration))


@iphone_exploit_bp.route('/crash-reports', methods=['POST'])
@login_required
def crash_reports():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().crash_reports(udid))


# ── Apps ─────────────────────────────────────────────────────────

@iphone_exploit_bp.route('/apps/list', methods=['POST'])
@login_required
def list_apps():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    app_type = data.get('type', 'user')
    return jsonify(_get_mgr().list_apps(udid, app_type=app_type))


@iphone_exploit_bp.route('/apps/install', methods=['POST'])
@login_required
def install_app():
    udid = request.form.get('udid', '').strip()
    if not udid:
        return jsonify({'error': 'No UDID provided'})
    f = request.files.get('file')
    if not f:
        return jsonify({'error': 'No file uploaded'})
    from core.paths import get_uploads_dir
    upload_path = str(get_uploads_dir() / f.filename)
    f.save(upload_path)
    return jsonify(_get_mgr().install_app(udid, upload_path))


@iphone_exploit_bp.route('/apps/uninstall', methods=['POST'])
@login_required
def uninstall_app():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    bundle_id = data.get('bundle_id', '').strip()
    if not bundle_id:
        return jsonify({'error': 'No bundle_id provided'})
    return jsonify(_get_mgr().uninstall_app(udid, bundle_id))


# ── Backup & Extraction ─────────────────────────────────────────

@iphone_exploit_bp.route('/backup/create', methods=['POST'])
@login_required
def backup_create():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    encrypted = data.get('encrypted', False)
    password = data.get('password', '')
    return jsonify(_get_mgr().create_backup(udid, encrypted=encrypted, password=password))


@iphone_exploit_bp.route('/backup/list', methods=['POST'])
@login_required
def backup_list():
    return jsonify(_get_mgr().list_backups())


@iphone_exploit_bp.route('/backup/sms', methods=['POST'])
@login_required
def backup_sms():
    data = request.get_json(silent=True) or {}
    backup_path = data.get('backup_path', '').strip()
    if not backup_path:
        return jsonify({'error': 'No backup_path provided'})
    return jsonify(_get_mgr().extract_backup_sms(backup_path))


@iphone_exploit_bp.route('/backup/contacts', methods=['POST'])
@login_required
def backup_contacts():
    data = request.get_json(silent=True) or {}
    backup_path = data.get('backup_path', '').strip()
    if not backup_path:
        return jsonify({'error': 'No backup_path provided'})
    return jsonify(_get_mgr().extract_backup_contacts(backup_path))


@iphone_exploit_bp.route('/backup/calls', methods=['POST'])
@login_required
def backup_calls():
    data = request.get_json(silent=True) or {}
    backup_path = data.get('backup_path', '').strip()
    if not backup_path:
        return jsonify({'error': 'No backup_path provided'})
    return jsonify(_get_mgr().extract_backup_call_log(backup_path))


@iphone_exploit_bp.route('/backup/notes', methods=['POST'])
@login_required
def backup_notes():
    data = request.get_json(silent=True) or {}
    backup_path = data.get('backup_path', '').strip()
    if not backup_path:
        return jsonify({'error': 'No backup_path provided'})
    return jsonify(_get_mgr().extract_backup_notes(backup_path))


@iphone_exploit_bp.route('/backup/files', methods=['POST'])
@login_required
def backup_files():
    data = request.get_json(silent=True) or {}
    backup_path = data.get('backup_path', '').strip()
    if not backup_path:
        return jsonify({'error': 'No backup_path provided'})
    domain = data.get('domain', '')
    path_filter = data.get('path_filter', '')
    return jsonify(_get_mgr().list_backup_files(backup_path, domain=domain, path_filter=path_filter))


@iphone_exploit_bp.route('/backup/extract-file', methods=['POST'])
@login_required
def backup_extract_file():
    data = request.get_json(silent=True) or {}
    backup_path = data.get('backup_path', '').strip()
    file_hash = data.get('file_hash', '').strip()
    if not backup_path or not file_hash:
        return jsonify({'error': 'Missing backup_path or file_hash'})
    output_name = data.get('output_name') or None
    return jsonify(_get_mgr().extract_backup_file(backup_path, file_hash, output_name=output_name))


# ── Filesystem ───────────────────────────────────────────────────

@iphone_exploit_bp.route('/fs/mount', methods=['POST'])
@login_required
def fs_mount():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().mount_filesystem(udid))


@iphone_exploit_bp.route('/fs/mount-app', methods=['POST'])
@login_required
def fs_mount_app():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    bundle_id = data.get('bundle_id', '').strip()
    if not bundle_id:
        return jsonify({'error': 'No bundle_id provided'})
    return jsonify(_get_mgr().mount_app_documents(udid, bundle_id))


@iphone_exploit_bp.route('/fs/unmount', methods=['POST'])
@login_required
def fs_unmount():
    data = request.get_json(silent=True) or {}
    mountpoint = data.get('mountpoint', '').strip()
    if not mountpoint:
        return jsonify({'error': 'No mountpoint provided'})
    _get_mgr().unmount_filesystem(mountpoint)
    return jsonify({'success': True, 'output': 'Unmounted'})


# ── Profiles ─────────────────────────────────────────────────────

@iphone_exploit_bp.route('/profiles/list', methods=['POST'])
@login_required
def profiles_list():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().list_profiles(udid))


@iphone_exploit_bp.route('/profiles/install', methods=['POST'])
@login_required
def profiles_install():
    udid = request.form.get('udid', '').strip()
    if not udid:
        return jsonify({'error': 'No UDID provided'})
    f = request.files.get('file')
    if not f:
        return jsonify({'error': 'No file uploaded'})
    from core.paths import get_uploads_dir
    upload_path = str(get_uploads_dir() / f.filename)
    f.save(upload_path)
    return jsonify(_get_mgr().install_profile(udid, upload_path))


@iphone_exploit_bp.route('/profiles/remove', methods=['POST'])
@login_required
def profiles_remove():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    profile_id = data.get('profile_id', '').strip()
    if not profile_id:
        return jsonify({'error': 'No profile_id provided'})
    return jsonify(_get_mgr().remove_profile(udid, profile_id))


# ── Network ──────────────────────────────────────────────────────

@iphone_exploit_bp.route('/port-forward', methods=['POST'])
@login_required
def port_forward():
    udid, err = _get_udid()
    if err:
        return err
    data = request.get_json(silent=True) or {}
    local_port = data.get('local_port')
    device_port = data.get('device_port')
    if not local_port or not device_port:
        return jsonify({'error': 'Missing local_port or device_port'})
    return jsonify(_get_mgr().port_forward(udid, int(local_port), int(device_port)))


# ── Recon ────────────────────────────────────────────────────────

@iphone_exploit_bp.route('/recon/export', methods=['POST'])
@login_required
def recon_export():
    udid, err = _get_udid()
    if err:
        return err
    return jsonify(_get_mgr().export_recon_report(udid))
