#!/usr/bin/python
# -*- coding: utf-8 -*-

# --------------------------------------------------------------------------- #
#    Isida-NG Jabber Bot (fork of iSida)                                      #
#    Original iSida Copyright (C) 2009-2015 diSabler <dsy@dsy.name>           #
#    Isida-NG Copyright (C) 2026 Luciferus <luciferus@ubunix.pro>             #
#    Project home: https://git.ubunix.pro/Luciferus/isida-ng                                #
# --------------------------------------------------------------------------- #

import time
import re
import os
import subprocess
import urllib.request

DEV_ROOM = 'devbot@conference.ubunix.pro'
DEV_ROOM_NICK = 'Isida-Feedback'
DEV_ROOM_PASS = ''
LOG_LINES = 200

# ============== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ==============

def _is_owner(room, nick):
    for base in megabase:
        if base[0] == room and base[1] == nick:
            return base[3] == 'owner'
    return False

def _get_room_jid(jid):
    return getRoom(jid)

def _get_bot_info():
    info = []
    info.append(f"Bot: {botName} {botVersion}")
    info.append(f"OS: {botOs}")
    info.append(f"Uptime: {un_unix(int(time.time() - starttime), '')}")
    info.append(f"Rooms: {cur_execute_fetchone('SELECT COUNT(*) FROM conference')[0]}")
    info.append(f"Threads: {th_cnt}")
    info.append(f"Errors: {thread_error_count}")
    return '\n'.join(info)

def _get_log_tail(lines=LOG_LINES):
    try:
        with open(LOG_FILENAME, 'r', encoding='utf-8', errors='ignore') as f:
            all_lines = f.readlines()
            clean_lines = []
            for line in all_lines[-lines:]:
                try:
                    clean_lines.append(line.encode('utf-8', errors='ignore').decode('utf-8'))
                except:
                    clean_lines.append('[BINARY DATA SKIPPED]')
            return ''.join(clean_lines)
    except Exception as e:
        return f"Error reading log: {str(e)}"

def _paste_to_pastebin(text, title=''):
    try:
        token = "Fg8q0R48KqDyMKweaFQKCndodGhxrXVwKt2FYz590xNu6sEpiuBZGCYdvFBL"
        boundary = '--' + str(time.time())
        body_parts = []
        body_parts.append(f'--{boundary}')
        body_parts.append('Content-Disposition: form-data; name="f"; filename="log.txt"')
        body_parts.append('Content-Type: text/plain')
        body_parts.append('')
        body_parts.append(text)
        body_parts.append(f'--{boundary}--')
        body = '\r\n'.join(body_parts)
        headers = {
            'Authorization': f'Bearer {token}',
            'Content-Type': f'multipart/form-data; boundary={boundary}'
        }
        req = urllib.request.Request(
            'https://paste.ubunix.pro',
            data=body.encode('utf-8', errors='ignore'),
            headers=headers,
            method='POST'
        )
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = resp.read().decode('utf-8').strip()
            if result:
                return result
        return None
    except Exception as e:
        pprint(f'*** paste.ubunix.pro error: {str(e)}', 'red')
        return None

def _check_limits(jid, nick):
    room = _get_room_jid(jid)
    now = int(time.time())

    records = cur_execute_fetchall(
        'SELECT time FROM adminmail_limits WHERE jid=%s ORDER BY time DESC',
        (jid,)
    )

    if not records:
        return True, None

    times = [r[0] for r in records]

    if times and now - times[0] < 10:
        wait = 10 - (now - times[0])
        return False, L('Please wait %s before sending another message.', '%s/%s' % (room, nick)) % un_unix(wait, '%s/%s' % (room, nick))

    hour_ago = now - 3600
    hour_count = sum(1 for t in times if t > hour_ago)
    if hour_count >= 30:
        return False, L('You have sent 3 messages in the last hour. Please try again later.', '%s/%s' % (room, nick))

    day_ago = now - 86400
    day_count = sum(1 for t in times if t > day_ago)
    if day_count >= 50:
        return False, L('You have sent 5 messages in the last 24 hours. Please try again tomorrow.', '%s/%s' % (room, nick))

    return True, None

def _add_limit_record(jid):
    now = int(time.time())
    cur_execute('INSERT INTO adminmail_limits (jid, time) VALUES (%s, %s)', (jid, now))

def _clean_old_limits():
    day_ago = int(time.time()) - 86400
    cur_execute('DELETE FROM adminmail_limits WHERE time < %s', (day_ago,))

# ============== РАБОТА С КОМНАТОЙ ==============

def _join_dev_room():
    pprint(f'*** devmail: joining {DEV_ROOM}', 'cyan')
    try:
        room_jid = f'{DEV_ROOM}/{DEV_ROOM_NICK}'
        join_result = join(room_jid, DEV_ROOM_PASS if DEV_ROOM_PASS else '')
        if join_result:
            pprint(f'*** devmail: join error: {join_result}', 'red')
            return False
        time.sleep(3)
        return True
    except Exception as e:
        pprint(f'*** devmail: join exception: {e}', 'red')
        return False

def _leave_dev_room():
    try:
        leave(DEV_ROOM, 'Message sent, leaving...')
        pprint('*** devmail: left room', 'cyan')
        return True
    except Exception as e:
        pprint(f'*** devmail: leave error: {e}', 'red')
        return False

def _send_to_dev_room(message):
    try:
        if isinstance(message, bytes):
            message = message.decode('utf-8', errors='ignore')
        elif not isinstance(message, str):
            message = str(message)

        send_msg('groupchat', DEV_ROOM, '', message)
        pprint('*** devmail: sent via send_msg', 'green')
        return True
    except Exception as e:
        pprint(f'*** devmail: send error: {e}', 'red')
        return False

# ============== ОСНОВНАЯ ФУНКЦИЯ ==============

def devmail(type, jid, nick, text):
    room = _get_room_jid(jid)

    if not _is_owner(room, nick):
        send_msg(type, jid, nick, L('Only room owners can send messages to the developer.', '%s/%s' % (room, nick)))
        return

    if len(text) > 1024:
        send_msg(type, jid, nick, L('Message is too long. Maximum 1024 characters.', '%s/%s' % (room, nick)))
        return

    can_send, error_msg = _check_limits(jid, nick)
    if not can_send:
        send_msg(type, jid, nick, error_msg)
        return

    _clean_old_limits()
    _add_limit_record(jid)

    bot_info = _get_bot_info()
    log_text = _get_log_tail()

    log_url = _paste_to_pastebin(log_text, 'Bot log')

    msg_lines = []
    msg_lines.append(f"Message from {nick} ({jid}):")
    msg_lines.append("")
    msg_lines.append(text)
    msg_lines.append("")
    msg_lines.append(f"Bot: {botName} {botVersion}")
    msg_lines.append(f"OS: {botOs}")
    msg_lines.append(f"Uptime: {un_unix(int(time.time() - starttime), '')}")
    msg_lines.append(f"Rooms: {cur_execute_fetchone('SELECT COUNT(*) FROM conference')[0]}")
    msg_lines.append(f"Threads: {th_cnt}")
    msg_lines.append(f"Errors: {thread_error_count}")

    if log_url:
        msg_lines.append("")
        msg_lines.append(f"Logs: {log_url}")

    msg = '\n'.join(msg_lines)

    try:
        if not _join_dev_room():
            send_msg(type, jid, nick, L('Failed to join developer room. Please try again later.', '%s/%s' % (room, nick)))
            return

        if not _send_to_dev_room(msg):
            send_msg(type, jid, nick, L('Failed to send message to developer room.', '%s/%s' % (room, nick)))
            _leave_dev_room()
            return

        time.sleep(1)
        _leave_dev_room()

    except Exception as e:
        pprint(f'*** devmail: error: {e}', 'red')
        _leave_dev_room()
        send_msg(type, jid, nick, L('Failed to send message to developer. Please try again later.', '%s/%s' % (room, nick)))
        return

    send_msg(type, jid, nick, L('Your message has been sent to the developer.', '%s/%s' % (room, nick)))

# ============== HELP ==============

def devmail_help_ru(type, jid, nick, text):
    room = _get_room_jid(jid)
    help_text = L('devmail — отправка сообщения разработчику бота.\n\n'
                  'Доступно только для овнеров комнаты.\n'
                  'Ограничения:\n'
                  '  • Максимальная длина сообщения: 1024 символа\n'
                  '  • Не более 1 сообщения в 10 секунд\n'
                  '  • Не более 3 сообщений в час\n'
                  '  • Не более 5 сообщений в сутки\n\n'
                  'Что отправляется:\n'
                  '  • Ваше сообщение\n'
                  '  • Информация о боте (версия, uptime, OS)\n'
                  '  • Логи бота (последние %s строк) на paste.ubunix.pro\n\n'
                  'Использование: devmail <текст сообщения>', '%s/%s' % (room, nick)) % LOG_LINES
    send_msg(type, jid, nick, help_text)

def devmail_help_en(type, jid, nick, text):
    room = _get_room_jid(jid)
    help_text = L('devmail — send a message to the bot developer.\n\n'
                  'Available only for room owners.\n'
                  'Limits:\n'
                  '  • Maximum message length: 1024 characters\n'
                  '  • No more than 1 message per 10 seconds\n'
                  '  • No more than 3 messages per hour\n'
                  '  • No more than 5 messages per day\n\n'
                  'What is sent:\n'
                  '  • Your message\n'
                  '  • Bot information (version, uptime, OS)\n'
                  '  • Bot logs (last %s lines) on paste.ubunix.pro\n\n'
                  'Usage: devmail <message text>', '%s/%s' % (room, nick)) % LOG_LINES
    send_msg(type, jid, nick, help_text)

# ============== ADMINMAIL ==============

def adminmail(type, jid, nick, text):
    if not text:
        send_msg(type, jid, nick, L('What?', '%s/%s' % (jid, nick)))
        return

    if len(text) > GT('amsg_limit_size'):
        text = text[:GT('amsg_limit_size')] + u'…'

    ga = get_level(jid, nick)
    fjid = getRoom(ga[1])
    tmp_lim = GT('amsg_limit')[ga[0]]

    am = cur_execute_fetchone('SELECT time FROM saytoowner WHERE jid=%s', (fjid,))
    if am:
        wt = int(am[0] - time.time())
        if wt >= 0:
            send_msg(type, jid, nick, L('Time limit exceeded. Wait: %s', '%s/%s' % (jid, nick)) % un_unix(wt, '%s/%s' % (jid, nick)))
            return
        else:
            cur_execute('DELETE FROM saytoowner WHERE jid=%s', (fjid,))

    cur_execute('INSERT INTO saytoowner VALUES (%s, %s)', (fjid, int(time.time()) + tmp_lim))

    msg = L('User %s (%s) from %s at %s send message to you: %s', '%s/%s' % (jid, nick)) % (
        nick, fjid, jid, time.strftime("%H:%M %d.%m.%y", time.localtime()), text
    )

    own = cur_execute_fetchall('SELECT jid FROM bot_owner')
    if own:
        for ajid in own:
            send_msg('chat', ajid[0], '', msg)
        send_msg(type, jid, nick, L('Sent', '%s/%s' % (jid, nick)))
    else:
        send_msg(type, jid, nick, L('Owner list is empty!', '%s/%s' % (jid, nick)))

# ============== ИНИЦИАЛИЗАЦИЯ БД ==============

def _init_db():
    cur_execute('''
        CREATE TABLE IF NOT EXISTS adminmail_limits (
            jid TEXT,
            time INTEGER
        )
    ''')

_init_db()

# ============== РЕГИСТРАЦИЯ ==============

global execute

execute = [
    (4, 'msgtoadmin', adminmail, 2, 'Send message to bot\'s owner\nmsgtoadmin text'),
    (8, 'devmail', devmail, 2, 'Send message to developer (room owners only)'),
    (8, 'devmail_help_ru', devmail_help_ru, 2, 'Show help for devmail command (Russian)'),
    (8, 'devmail_help_en', devmail_help_en, 2, 'Show help for devmail command (English)'),
]
