import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import json
import sqlite3
import uuid
import hashlib
import datetime
import traceback
import mimetypes
import requests
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-change-this'
app.config['UPLOAD_FOLDER'] = '/opt/sitechat/uploads'
app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024

CORS(app, origins='*', methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
     allow_headers=['Content-Type', 'Authorization'])

DB_PATH = '/opt/sitechat/database/sqlite.db'
UPLOAD_FOLDER = '/opt/sitechat/uploads'

os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)

def get_db():
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row
    return conn

def get_client_ip():
    if request.headers.get('X-Forwarded-For'):
        ip = request.headers.get('X-Forwarded-For').split(',')[0].strip()
    elif request.headers.get('X-Real-IP'):
        ip = request.headers.get('X-Real-IP')
    else:
        ip = request.remote_addr
    return ip

def get_geo_info(ip):
    if ip == '127.0.0.1' or ip.startswith('192.168.') or ip.startswith('10.') or ip.startswith('172.'):
        return {'city': 'Локальная сеть', 'country': 'LAN', 'region': '', 'full': 'Локальная сеть'}
    try:
        response = requests.get(f'http://ip-api.com/json/{ip}', timeout=3)
        if response.status_code == 200:
            data = response.json()
            if data.get('status') == 'success':
                city = data.get('city', '')
                country = data.get('country', '')
                region = data.get('regionName', '')
                return {'city': city, 'country': country, 'region': region, 'full': f"{city}, {country}" if city else country}
    except Exception as e:
        print(f"Geo error: {e}")
    return {'city': '', 'country': '', 'region': '', 'full': 'Неизвестно'}

@app.route('/', methods=['GET', 'OPTIONS'])
def index():
    if request.method == 'OPTIONS':
        return '', 200
    return jsonify({'status': 'ok', 'message': 'Chat server is running'})

@app.route('/admin', methods=['GET', 'OPTIONS'])
def admin():
    if request.method == 'OPTIONS':
        return '', 200
    try:
        with open('/opt/sitechat/templates/admin.html', 'r', encoding='utf-8') as f:
            return f.read()
    except Exception as e:
        return jsonify({'error': str(e)}), 404

@app.route('/api/check_db', methods=['GET', 'OPTIONS'])
def check_db():
    if request.method == 'OPTIONS':
        return '', 200
    return jsonify({'exists': os.path.exists(DB_PATH), 'integrity': True})

@app.route('/api/admin/login', methods=['POST', 'OPTIONS'])
def admin_login():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    if data.get('username') == 'admin' and data.get('password') == 'admin123':
        token = str(uuid.uuid4()) + str(uuid.uuid4()).replace('-', '')
        return jsonify({'token': token})
    return jsonify({'error': 'Invalid credentials'}), 401

@app.route('/api/admin/users', methods=['GET', 'OPTIONS'])
def get_users():
    if request.method == 'OPTIONS':
        return '', 200
    conn = get_db()
    users = conn.execute('SELECT user_id, created_at, last_seen, last_ip, last_location, city, country FROM users ORDER BY created_at DESC').fetchall()
    result = []
    for user in users:
        user_dict = dict(user)
        last = conn.execute('SELECT text, timestamp, sender FROM messages WHERE user_id = ? ORDER BY timestamp DESC LIMIT 1', (user_dict['user_id'],)).fetchone()
        if last:
            user_dict['last_message'] = last['text'][:50] if last['text'] else '[Файл]'
            user_dict['last_message_time'] = last['timestamp']
        else:
            user_dict['last_message'] = ''
            user_dict['last_message_time'] = ''
        user_dict['has_unread'] = conn.execute('SELECT COUNT(*) FROM messages WHERE user_id = ? AND sender="user" AND is_read=0', (user_dict['user_id'],)).fetchone()[0] > 0
        result.append(user_dict)
    conn.close()
    return jsonify(result)

@app.route('/api/admin/users_paginated', methods=['POST', 'OPTIONS'])
def get_users_paginated():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    page = data.get('page', 1)
    limit = data.get('limit', 25)
    offset = (page - 1) * limit
    
    conn = get_db()
    cursor = conn.cursor()
    
    cursor.execute('SELECT COUNT(*) as total FROM users')
    total = cursor.fetchone()['total']
    
    cursor.execute('''
        SELECT user_id, created_at, last_seen, last_ip, last_location, city, country 
        FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?
    ''', (limit, offset))
    users = cursor.fetchall()
    
    result = []
    for user in users:
        user_dict = dict(user)
        last = cursor.execute('SELECT text, timestamp, sender FROM messages WHERE user_id = ? ORDER BY timestamp DESC LIMIT 1', (user_dict['user_id'],)).fetchone()
        if last:
            user_dict['last_message'] = last['text'][:50] if last['text'] else '[Файл]'
            user_dict['last_message_time'] = last['timestamp']
        else:
            user_dict['last_message'] = ''
            user_dict['last_message_time'] = ''
        user_dict['has_unread'] = cursor.execute('SELECT COUNT(*) FROM messages WHERE user_id = ? AND sender="user" AND is_read=0', (user_dict['user_id'],)).fetchone()[0] > 0
        result.append(user_dict)
    
    conn.close()
    
    return jsonify({
        'users': result,
        'total': total,
        'page': page,
        'limit': limit,
        'total_pages': (total + limit - 1) // limit if limit > 0 else 1
    })

@app.route('/api/admin/users_with_unread', methods=['GET', 'OPTIONS'])
def get_users_with_unread():
    if request.method == 'OPTIONS':
        return '', 200
    conn = get_db()
    
    users = conn.execute('''
        SELECT DISTINCT u.user_id, u.created_at, u.last_seen, u.last_ip, u.last_location, u.city, u.country
        FROM users u
        INNER JOIN messages m ON u.user_id = m.user_id
        WHERE m.sender = 'user' AND m.is_read = 0
        ORDER BY m.timestamp DESC
    ''').fetchall()
    
    result = []
    for user in users:
        user_dict = dict(user)
        last = conn.execute('SELECT text, timestamp, sender FROM messages WHERE user_id = ? ORDER BY timestamp DESC LIMIT 1', (user_dict['user_id'],)).fetchone()
        if last:
            user_dict['last_message'] = last['text'][:50] if last['text'] else '[Файл]'
            user_dict['last_message_time'] = last['timestamp']
        else:
            user_dict['last_message'] = ''
            user_dict['last_message_time'] = ''
        user_dict['has_unread'] = True
        result.append(user_dict)
    
    conn.close()
    return jsonify(result)

@app.route('/api/admin/users_with_messages', methods=['GET', 'OPTIONS'])
def get_users_with_messages():
    """Получение всех пользователей с реальными сообщениями (не системными)"""
    if request.method == 'OPTIONS':
        return '', 200
    conn = get_db()
    cursor = conn.cursor()
    
    cursor.execute('''
        SELECT DISTINCT u.user_id, u.created_at, u.last_seen, u.last_ip, u.last_location, u.city, u.country
        FROM users u
        INNER JOIN messages m ON u.user_id = m.user_id
        WHERE m.sender = 'user' OR m.sender = 'admin'
        ORDER BY u.created_at DESC
    ''')
    users = cursor.fetchall()
    
    result = []
    for user in users:
        user_dict = dict(user)
        last = cursor.execute('SELECT text, timestamp, sender FROM messages WHERE user_id = ? AND (sender = "user" OR sender = "admin") ORDER BY timestamp DESC LIMIT 1', (user_dict['user_id'],)).fetchone()
        if last:
            user_dict['last_message'] = last['text'][:50] if last['text'] else '[Файл]'
            user_dict['last_message_time'] = last['timestamp']
        else:
            user_dict['last_message'] = ''
            user_dict['last_message_time'] = ''
        user_dict['has_unread'] = cursor.execute('SELECT COUNT(*) FROM messages WHERE user_id = ? AND sender="user" AND is_read=0', (user_dict['user_id'],)).fetchone()[0] > 0
        result.append(user_dict)
    
    conn.close()
    return jsonify(result)

@app.route('/api/admin/new_users', methods=['GET', 'OPTIONS'])
def get_new_users():
    """Получение новых пользователей (с момента последнего запроса)"""
    if request.method == 'OPTIONS':
        return '', 200
    
    last_check = request.args.get('last_check', '')
    
    conn = get_db()
    cursor = conn.cursor()
    
    if last_check:
        cursor.execute('''
            SELECT DISTINCT u.user_id, u.created_at, u.last_seen, u.last_ip, u.last_location, u.city, u.country
            FROM users u
            INNER JOIN messages m ON u.user_id = m.user_id
            WHERE m.timestamp > ?
            ORDER BY m.timestamp DESC
        ''', (last_check,))
    else:
        cursor.execute('''
            SELECT DISTINCT u.user_id, u.created_at, u.last_seen, u.last_ip, u.last_location, u.city, u.country
            FROM users u
            INNER JOIN messages m ON u.user_id = m.user_id
            ORDER BY m.timestamp DESC
            LIMIT 50
        ''')
    
    users = cursor.fetchall()
    
    result = []
    for user in users:
        user_dict = dict(user)
        last = cursor.execute('SELECT text, timestamp, sender FROM messages WHERE user_id = ? ORDER BY timestamp DESC LIMIT 1', (user_dict['user_id'],)).fetchone()
        if last:
            user_dict['last_message'] = last['text'][:50] if last['text'] else '[Файл]'
            user_dict['last_message_time'] = last['timestamp']
        else:
            user_dict['last_message'] = ''
            user_dict['last_message_time'] = ''
        user_dict['has_unread'] = cursor.execute('SELECT COUNT(*) FROM messages WHERE user_id = ? AND sender="user" AND is_read=0', (user_dict['user_id'],)).fetchone()[0] > 0
        result.append(user_dict)
    
    conn.close()
    return jsonify(result)

@app.route('/api/admin/search', methods=['POST', 'OPTIONS'])
def search_users():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    query = data.get('query', '').strip()
    
    if not query:
        return jsonify({'users': []})
    
    conn = get_db()
    cursor = conn.cursor()
    
    cursor.execute('SELECT user_id FROM users WHERE user_id LIKE ?', (f'%{query}%',))
    users_by_id = [row['user_id'] for row in cursor.fetchall()]
    
    cursor.execute('''
        SELECT DISTINCT user_id FROM messages 
        WHERE text LIKE ? AND sender != 'system'
        ORDER BY timestamp DESC
    ''', (f'%{query}%',))
    users_by_message = [row['user_id'] for row in cursor.fetchall()]
    
    all_user_ids = list(set(users_by_id + users_by_message))
    
    result = []
    for user_id in all_user_ids:
        cursor.execute('SELECT user_id, created_at, last_seen, last_ip, last_location, city, country FROM users WHERE user_id = ?', (user_id,))
        user = cursor.fetchone()
        if user:
            user_dict = dict(user)
            last = cursor.execute('SELECT text, timestamp, sender FROM messages WHERE user_id = ? ORDER BY timestamp DESC LIMIT 1', (user_id,)).fetchone()
            if last:
                user_dict['last_message'] = last['text'][:50] if last['text'] else '[Файл]'
                user_dict['last_message_time'] = last['timestamp']
            else:
                user_dict['last_message'] = ''
                user_dict['last_message_time'] = ''
            user_dict['has_unread'] = cursor.execute('SELECT COUNT(*) FROM messages WHERE user_id = ? AND sender="user" AND is_read=0', (user_id,)).fetchone()[0] > 0
            result.append(user_dict)
    
    conn.close()
    return jsonify({'users': result, 'query': query})

@app.route('/api/admin/messages/<user_id>', methods=['GET', 'OPTIONS'])
def get_user_messages(user_id):
    if request.method == 'OPTIONS':
        return '', 200
    conn = get_db()
    messages = conn.execute('SELECT message_id as id, sender, text, file_info as file, timestamp FROM messages WHERE user_id = ? ORDER BY timestamp ASC', (user_id,)).fetchall()
    result = []
    for msg in messages:
        msg_dict = dict(msg)
        if msg_dict.get('file'):
            try:
                msg_dict['file'] = json.loads(msg_dict['file'])
            except:
                pass
        result.append(msg_dict)
    conn.close()
    return jsonify(result)

@app.route('/api/admin/send', methods=['POST', 'OPTIONS'])
def admin_send_message():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    text = data.get('message')
    msg_id = str(uuid.uuid4())
    timestamp = datetime.datetime.now().isoformat()
    conn = get_db()
    conn.execute('INSERT INTO messages (user_id, message_id, sender, text, timestamp, is_read) VALUES (?, ?, ?, ?, ?, ?)',
                 (user_id, msg_id, 'admin', text, timestamp, 1))
    conn.commit()
    conn.close()
    return jsonify({'success': True, 'id': msg_id, 'timestamp': timestamp})

@app.route('/api/admin/mark_read/<user_id>', methods=['POST', 'OPTIONS'])
def mark_user_read(user_id):
    if request.method == 'OPTIONS':
        return '', 200
    conn = get_db()
    conn.execute('UPDATE messages SET is_read = 1 WHERE user_id = ? AND sender = "user"', (user_id,))
    conn.commit()
    conn.close()
    return jsonify({'success': True})

@app.route('/api/admin/edit_message', methods=['PUT', 'OPTIONS'])
def admin_edit_message():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    message_id = data.get('message_id')
    new_text = data.get('new_text')
    conn = get_db()
    conn.execute('UPDATE messages SET text = ?, is_edited = 1, edited_at = ? WHERE user_id = ? AND message_id = ?',
                 (new_text, datetime.datetime.now().isoformat(), user_id, message_id))
    conn.commit()
    conn.close()
    return jsonify({'success': True})

@app.route('/api/admin/delete_message', methods=['DELETE', 'OPTIONS'])
def admin_delete_message():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    message_id = data.get('message_id')
    conn = get_db()
    conn.execute('DELETE FROM messages WHERE user_id = ? AND message_id = ?', (user_id, message_id))
    conn.commit()
    conn.close()
    return jsonify({'success': True})

@app.route('/api/register', methods=['POST', 'OPTIONS'])
def register_user():
    if request.method == 'OPTIONS':
        return '', 200
    user_id = str(uuid.uuid4())[:8]
    client_ip = get_client_ip()
    geo_info = get_geo_info(client_ip)
    timestamp = datetime.datetime.now().isoformat()
    conn = get_db()
    conn.execute('INSERT INTO users (user_id, created_at, last_seen, last_ip, last_location, city, country, region) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
                 (user_id, timestamp, timestamp, client_ip, geo_info.get('full', ''), geo_info.get('city', ''), geo_info.get('country', ''), geo_info.get('region', '')))
    conn.commit()
    conn.close()
    
    welcome_msg_id = str(uuid.uuid4())
    welcome_text = 'Для возможности просмотра истории сообщений <a href="#" onclick="showPasswordForm(); return false;" style="color: #25D366; text-decoration: underline; cursor: pointer;">задайте пароль</a>.\n\nЗапомните свой ID для последующего использования в чате.\nДля восстановления истории сообщений измените ID в заголовке окна и введите пароль.'
    
    conn = get_db()
    conn.execute('INSERT INTO messages (user_id, message_id, sender, text, timestamp, is_read) VALUES (?, ?, ?, ?, ?, ?)',
                 (user_id, welcome_msg_id, 'system', welcome_text, timestamp, 1))
    conn.commit()
    conn.close()
    return jsonify({'user_id': user_id, 'profile': {'user_id': user_id}, 'history': []})

@app.route('/api/login', methods=['POST', 'OPTIONS'])
def user_login():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    password = data.get('password', '')
    
    conn = get_db()
    user = conn.execute('SELECT * FROM users WHERE user_id = ?', (user_id,)).fetchone()
    if not user:
        conn.close()
        return jsonify({'error': 'User not found'}), 404
    
    user_dict = dict(user)
    if user_dict.get('password_hash'):
        if not password:
            conn.close()
            return jsonify({'error': 'Password required'}), 401
        password_hash = hashlib.sha256(password.encode()).hexdigest()
        if password_hash != user_dict.get('password_hash'):
            conn.close()
            return jsonify({'error': 'Invalid password'}), 401
    
    client_ip = get_client_ip()
    geo_info = get_geo_info(client_ip)
    conn.execute('UPDATE users SET last_seen = ?, last_ip = ?, last_location = ?, city = ?, country = ?, region = ? WHERE user_id = ?',
                 (datetime.datetime.now().isoformat(), client_ip, geo_info.get('full', ''), geo_info.get('city', ''), geo_info.get('country', ''), geo_info.get('region', ''), user_id))
    conn.commit()
    
    messages = conn.execute('SELECT message_id as id, sender, text, file_info as file, timestamp FROM messages WHERE user_id = ? ORDER BY timestamp ASC', (user_id,)).fetchall()
    result = []
    for msg in messages:
        msg_dict = dict(msg)
        if msg_dict.get('file'):
            try:
                msg_dict['file'] = json.loads(msg_dict['file'])
            except:
                pass
        result.append(msg_dict)
    conn.close()
    return jsonify({'user_id': user_id, 'profile': user_dict, 'history': result})

@app.route('/api/send_message', methods=['POST', 'OPTIONS'])
def send_message():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    message = data.get('message')
    sender = data.get('sender', 'user')
    msg_id = str(uuid.uuid4())
    text = message.get('text', '')
    timestamp = datetime.datetime.now().isoformat()
    conn = get_db()
    conn.execute('INSERT INTO messages (user_id, message_id, sender, text, timestamp, is_read) VALUES (?, ?, ?, ?, ?, ?)',
                 (user_id, msg_id, sender, text, timestamp, 0 if sender == 'user' else 1))
    conn.commit()
    conn.close()
    return jsonify({'id': msg_id, 'sender': sender, 'text': text, 'timestamp': timestamp})

@app.route('/api/edit_message', methods=['PUT', 'OPTIONS'])
def edit_message():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    message_id = data.get('message_id')
    new_text = data.get('new_text')
    conn = get_db()
    conn.execute('UPDATE messages SET text = ?, is_edited = 1, edited_at = ? WHERE user_id = ? AND message_id = ?',
                 (new_text, datetime.datetime.now().isoformat(), user_id, message_id))
    conn.commit()
    conn.close()
    return jsonify({'success': True})

@app.route('/api/delete_message', methods=['DELETE', 'OPTIONS'])
def delete_message():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    message_id = data.get('message_id')
    conn = get_db()
    conn.execute('DELETE FROM messages WHERE user_id = ? AND message_id = ?', (user_id, message_id))
    conn.commit()
    conn.close()
    return jsonify({'success': True})

@app.route('/api/set_password', methods=['POST', 'OPTIONS'])
def set_password():
    if request.method == 'OPTIONS':
        return '', 200
    data = request.json
    user_id = data.get('user_id')
    password = data.get('password')
    confirm = data.get('confirm')
    if not password or password != confirm or len(password) < 4:
        return jsonify({'error': 'Invalid password'}), 400
    password_hash = hashlib.sha256(password.encode()).hexdigest()
    conn = get_db()
    conn.execute('UPDATE users SET password_hash = ? WHERE user_id = ?', (password_hash, user_id))
    conn.commit()
    conn.close()
    return jsonify({'success': True})

@app.route('/api/upload_file', methods=['POST', 'OPTIONS'])
def upload_file():
    if request.method == 'OPTIONS':
        return '', 200
    user_id = request.form.get('user_id')
    file = request.files.get('file')
    sender = request.form.get('sender', 'user')
    if not file:
        return jsonify({'error': 'No file'}), 400
    file_id = str(uuid.uuid4())
    original_filename = file.filename
    extension = original_filename.split('.')[-1] if '.' in original_filename else ''
    saved_filename = f"{file_id}.{extension}" if extension else file_id
    file_path = os.path.join(UPLOAD_FOLDER, saved_filename)
    file.save(file_path)
    file_info = {
        'id': file_id, 'filename': original_filename, 'saved_name': saved_filename,
        'url': f'/api/file/{file_id}', 'preview_url': f'/api/file/preview/{file_id}',
        'size': os.path.getsize(file_path), 'type': file.content_type
    }
    msg_id = str(uuid.uuid4())
    timestamp = datetime.datetime.now().isoformat()
    conn = get_db()
    conn.execute('INSERT INTO messages (user_id, message_id, sender, text, file_info, timestamp, is_read) VALUES (?, ?, ?, ?, ?, ?, ?)',
                 (user_id, msg_id, sender, '', json.dumps(file_info), timestamp, 0 if sender == 'user' else 1))
    conn.commit()
    conn.close()
    return jsonify({'id': msg_id, 'sender': sender, 'file': file_info, 'timestamp': timestamp})

@app.route('/api/file/<file_id>')
def get_file(file_id):
    for filename in os.listdir(UPLOAD_FOLDER):
        if filename.startswith(file_id):
            return send_from_directory(UPLOAD_FOLDER, filename)
    return jsonify({'error': 'File not found'}), 404

@app.route('/api/file/preview/<file_id>')
def preview_file(file_id):
    for filename in os.listdir(UPLOAD_FOLDER):
        if filename.startswith(file_id):
            return send_from_directory(UPLOAD_FOLDER, filename)
    return jsonify({'error': 'File not found'}), 404

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000, debug=False)
