#!/usr/bin/env python3
"""Interactive Linux client for the owner's Agent Hub."""

import getpass
import json
import os
import platform
import signal
import subprocess
import sys
import time
import urllib.error
import urllib.request
from pathlib import Path

SERVER = 'https://147-45-229-94.sslip.io'
STORE = Path.home() / '.config' / 'agent-hub'
TOKEN_FILE = STORE / 'device-token'
IS_ANDROID = 'com.termux' in os.environ.get('PREFIX', '') or bool(os.environ.get('ANDROID_ROOT'))
DEVICE_PLATFORM = 'android' if IS_ANDROID else 'linux'


def request(path, token=None, body=None):
    data = json.dumps(body).encode() if body is not None else None
    headers = {'Content-Type': 'application/json'} if data else {}
    if token:
        headers['Authorization'] = 'Bearer ' + token
    req = urllib.request.Request(SERVER + path, data=data, headers=headers)
    with urllib.request.urlopen(req, timeout=20) as response:
        return json.loads(response.read())


def enroll():
    if TOKEN_FILE.exists():
        return TOKEN_FILE.read_text().strip()
    print('Подключение к личному Agent Hub:', SERVER)
    print('Каждая команда будет показана в этом терминале и потребует подтверждения.')
    answer = input('Подключить этот Linux-компьютер? [y/N] ').strip().lower()
    if answer not in ('y', 'yes', 'д', 'да'):
        raise SystemExit('Подключение отменено.')
    code = sys.argv[1] if len(sys.argv) > 1 else getpass.getpass('Одноразовый код: ')
    name = platform.node()[:55] + (' (Android)' if IS_ANDROID else ' (Linux)')
    result = request('/api/enroll', body={'code': code, 'name': name, 'platform': DEVICE_PLATFORM, 'approval_mode': 'chat'})
    STORE.mkdir(parents=True, exist_ok=True, mode=0o700)
    TOKEN_FILE.write_text(result['token'])
    TOKEN_FILE.chmod(0o600)
    return result['token']


def execute(command, chat_approved=False):
    print('\n' + '=' * 72)
    print('Agent Hub предлагает команду:\n')
    print(command)
    print('=' * 72)
    if not chat_approved:
        answer = input('Разрешить выполнение с правами текущего пользователя? [y/N] ').strip().lower()
        if answer not in ('y', 'yes', 'д', 'да'):
            return False, 'Пользователь отклонил команду.'
    else:
        print('Команда уже разрешена владельцем в чате Agent Hub.')
    try:
        bash = str(Path(os.environ.get('PREFIX', '/usr')) / 'bin/bash') if IS_ANDROID else '/bin/bash'
        process = subprocess.Popen(
            [bash, '-c', command], text=True, stdout=subprocess.PIPE,
            stderr=subprocess.PIPE, cwd=str(Path.home()), start_new_session=True,
        )
        try:
            stdout, stderr = process.communicate(timeout=60)
        except subprocess.TimeoutExpired:
            os.killpg(process.pid, signal.SIGTERM)
            stdout, stderr = process.communicate(timeout=5)
            output = f'Команда остановлена по лимиту 60 секунд. Уже внесённые изменения не отменены.\n{stdout}\n{stderr}'
            return True, output[:90000]
        output = f'Exit code: {process.returncode}\n{stdout}\n{stderr}'
        return True, output[:90000]
    except Exception as error:
        return True, str(error)[:90000]


def main():
    token = enroll()
    print('Agent Hub подключён. Оставьте этот терминал открытым. Ctrl+C отключает устройство.')
    while True:
        try:
            pending = request('/device/poll', token=token)
            job = pending.get('command')
            if job:
                approved, result = execute(job['command'], bool(job.get('chat_approved')))
                request('/device/result', token=token, body={
                    'id': job['id'], 'approved': approved, 'result': result,
                })
                print('Результат отправлен в Agent Hub.')
            time.sleep(3)
        except urllib.error.HTTPError as error:
            if error.code == 403:
                raise SystemExit('Доступ отозван в Agent Hub.')
            print('Ошибка соединения:', error, file=sys.stderr)
            time.sleep(5)
        except (urllib.error.URLError, TimeoutError) as error:
            print('Сервер временно недоступен:', error, file=sys.stderr)
            time.sleep(5)


if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print('\nAgent Hub отключён.')
