#!/usr/bin/env python3
"""SEO Bot worker - SSH test, cPanel kurulum, W7 yukleme, AI SEO kuyrugu."""
from __future__ import annotations

import json
import re
import sqlite3
import sys
import time
from pathlib import Path

try:
    import paramiko
except ImportError:
    print('paramiko gerekli: pip install paramiko')
    sys.exit(1)

ROOT = Path(__file__).resolve().parent.parent
DB_PATH = ROOT / 'data' / 'panel.sqlite'
CONFIG_PATH = ROOT / 'config.php'


def load_secret() -> str:
    if not CONFIG_PATH.is_file():
        return ''
    text = CONFIG_PATH.read_text(encoding='utf-8', errors='replace')
    m = re.search(r"'secret_key'\s*=>\s*'([^']*)'", text)
    return m.group(1) if m else ''


def decrypt(enc: str, secret: str) -> str:
    if not enc or not secret:
        return enc
    try:
        import base64
        from hashlib import sha256
        from Crypto.Cipher import AES  # optional
    except Exception:
        return enc
    return enc  # PHP openssl - worker uses plain for now if not encrypted


def ssh_run(ip: str, user: str, password: str, port: int, commands: list[str], timeout: int = 30) -> tuple[bool, str]:
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        client.connect(ip, port=port, username=user, password=password, timeout=timeout, allow_agent=False, look_for_keys=False)
        out = []
        for cmd in commands:
            stdin, stdout, stderr = client.exec_command(cmd, timeout=timeout)
            o = stdout.read().decode('utf-8', errors='replace')
            e = stderr.read().decode('utf-8', errors='replace')
            code = stdout.channel.recv_exit_status()
            out.append(f'$ {cmd}\n{o}{e}\nexit={code}')
            if code != 0 and 'reboot' not in cmd.lower():
                return False, '\n'.join(out)
        return True, '\n'.join(out)
    except Exception as exc:
        return False, str(exc)
    finally:
        client.close()


def wait_server(ip: str, user: str, password: str, port: int, attempts: int = 7, delay: int = 60) -> bool:
    for i in range(attempts):
        print(f'  Bekleniyor {i+1}/{attempts}...')
        time.sleep(delay)
        ok, _ = ssh_run(ip, user, password, port, ['echo ok'], timeout=15)
        if ok:
            return True
    return False


def process_ssh_test(conn: sqlite3.Connection, server: dict) -> None:
    pwd = server['ssh_pass']  # TODO: decrypt if encrypted
    ok, log = ssh_run(server['ip'], server['ssh_user'], pwd, server['ssh_port'], ['uname -a'])
    status = 'online' if ok else 'offline'
    conn.execute(
        'UPDATE servers SET status=?, last_check_at=datetime("now"), last_error=? WHERE id=?',
        (status, '' if ok else log[:500], server['id']),
    )
    print(f"SSH test {server['ip']}: {'OK' if ok else 'FAIL'}")


def process_provision_dns(conn: sqlite3.Connection, server: dict, hostname: str) -> None:
    pwd = server['ssh_pass']
    cmds = [
        'cat > /etc/resolv.conf <<EOF\nnameserver 1.1.1.1\nnameserver 1.0.0.1\nnameserver 8.8.8.8\nnameserver 8.8.4.4\nEOF',
        'chattr +i /etc/resolv.conf',
        f'hostnamectl set-hostname {hostname}',
        'dnf clean all',
        'dnf update -y',
        'reboot',
    ]
    ok, log = ssh_run(server['ip'], server['ssh_user'], pwd, server['ssh_port'], cmds[:-1])
    if ok:
        ssh_run(server['ip'], server['ssh_user'], pwd, server['ssh_port'], ['reboot'], timeout=5)
        conn.execute('UPDATE servers SET status=?, provision_log=? WHERE id=?',
                     ('provisioning_update', 'Reboot sonrasi bekleniyor...', server['id']))
        if wait_server(server['ip'], server['ssh_user'], pwd, server['ssh_port']):
            conn.execute('UPDATE servers SET status=?, provision_log=? WHERE id=?',
                         ('provisioning_cpanel', 'cPanel indiriliyor...', server['id']))
            ok2, log2 = ssh_run(server['ip'], server['ssh_user'], pwd, server['ssh_port'], [
                'cd /home && curl -o latest -L https://securedownloads.cpanel.net/latest',
                'sh latest',
            ], timeout=3600)
            conn.execute('UPDATE servers SET status=?, provision_log=? WHERE id=?',
                         ('cpanel_license_wait', log2[:800] if ok2 else log2[:500], server['id']))
    else:
        conn.execute('UPDATE servers SET status=?, last_error=? WHERE id=?',
                     ('offline', log[:500], server['id']))


def process_firewall(conn: sqlite3.Connection, server: dict) -> None:
    pwd = server['ssh_pass']
    cmds = [
        'dnf install firewalld -y',
        'systemctl enable firewalld',
        'systemctl start firewalld',
        'firewall-cmd --permanent --add-service=ssh',
        'firewall-cmd --permanent --add-port=2087/tcp',
        'firewall-cmd --permanent --add-port=2083/tcp',
        'firewall-cmd --permanent --add-service=http',
        'firewall-cmd --permanent --add-service=https',
        'firewall-cmd --reload',
        'reboot',
    ]
    ok, log = ssh_run(server['ip'], server['ssh_user'], pwd, server['ssh_port'], cmds[:-1])
    if ok:
        ssh_run(server['ip'], server['ssh_user'], pwd, server['ssh_port'], ['reboot'], timeout=5)
        if wait_server(server['ip'], server['ssh_user'], pwd, server['ssh_port'], attempts=7, delay=30):
            conn.execute('UPDATE servers SET status=?, is_ready=1, cpanel_ready=1, provision_log=? WHERE id=?',
                         ('ready', 'Kurulum tamamlandi', server['id']))
    else:
        conn.execute('UPDATE servers SET last_error=? WHERE id=?', (log[:500], server['id']))


def main() -> int:
    if not DB_PATH.is_file():
        print(f'Veritabani yok: {DB_PATH}')
        return 1
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row
    jobs = conn.execute("SELECT * FROM jobs WHERE status='pending' ORDER BY id LIMIT 10").fetchall()
    if not jobs:
        print('Bekleyen is yok.')
        return 0
    for job in jobs:
        jid, jtype = job['id'], job['job_type']
        tid = job['target_id']
        print(f'Is #{jid}: {jtype}')
        conn.execute("UPDATE jobs SET status='running', updated_at=datetime('now') WHERE id=?", (jid,))
        conn.commit()
        try:
            if jtype == 'ssh_test':
                s = conn.execute('SELECT * FROM servers WHERE id=?', (tid,)).fetchone()
                if s:
                    process_ssh_test(conn, dict(s))
            elif jtype == 'provision_cpanel':
                s = conn.execute('SELECT * FROM servers WHERE id=?', (tid,)).fetchone()
                payload = json.loads(job['payload'] or '{}')
                if s:
                    process_provision_dns(conn, dict(s), payload.get('hostname', 'server.local'))
            elif jtype == 'firewall_setup':
                s = conn.execute('SELECT * FROM servers WHERE id=?', (tid,)).fetchone()
                if s:
                    process_firewall(conn, dict(s))
            elif jtype == 'w7_upload':
                conn.execute("UPDATE domains SET seo_status='w7_bekliyor' WHERE id=?", (tid,))
                print('  W7 yukleme: whm_bot2 entegrasyonu ile tamamlanacak')
            elif jtype == 'seo_generate':
                conn.execute("UPDATE domains SET seo_status='seo_kuyrukta' WHERE id=?", (tid,))
                print('  SEO: PHP panel veya genisletilmis worker ile tamamlanacak')
            conn.execute("UPDATE jobs SET status='done', updated_at=datetime('now') WHERE id=?", (jid,))
        except Exception as exc:
            conn.execute("UPDATE jobs SET status='failed', result=?, updated_at=datetime('now') WHERE id=?",
                         (str(exc)[:500], jid))
        conn.commit()
    conn.close()
    return 0


if __name__ == '__main__':
    raise SystemExit(main())
