#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import uuid
import json
import re
import shutil
import traceback
import mimetypes
from datetime import datetime
from flask import Flask, render_template_string, request, redirect, url_for, session, send_from_directory, jsonify, abort
from werkzeug.utils import secure_filename

# Принудительно устанавливаем UTF-8 для вывода
if sys.version_info[0] >= 3:
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

os.environ['PYTHONIOENCODING'] = 'utf-8'
os.environ['LANG'] = 'ru_RU.UTF-8'
os.environ['LC_ALL'] = 'ru_RU.UTF-8'

# --- [BLOCK: CONFIG & PATHS] ---
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
os.chdir(BASE_DIR)

CONFIG = {
    'UPLOAD_FOLDER': os.path.join(BASE_DIR, 'uploads'),
    'SHARES_FILE': os.path.join(BASE_DIR, 'shares.json'),
    'SHARED_FOLDERS_FILE': os.path.join(BASE_DIR, 'shared_folders.json'),
    'USERS_FILE': os.path.join(BASE_DIR, 'users.json'),
    'SECRET_KEY': 'fm-v24-final-stable'
}

app = Flask(__name__)
app.secret_key = CONFIG['SECRET_KEY']
app.config['JSON_AS_ASCII'] = False

os.makedirs(CONFIG['UPLOAD_FOLDER'], exist_ok=True)

# --- [BLOCK: USER DATABASE HELPERS] ---
def get_users():
    if not os.path.exists(CONFIG['USERS_FILE']):
        default_users = [{'name': 'Администратор', 'login': 'admin', 'password': 'админ@2026', 'quota': ''}]
        save_users(default_users)
        return default_users
    try:
        with open(CONFIG['USERS_FILE'], 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Ошибка чтения users.json: {e}")
        return []

def save_users(users):
    with open(CONFIG['USERS_FILE'], 'w', encoding='utf-8') as f:
        json.dump(users, f, ensure_ascii=False, indent=2)

def get_user_quota(login):
    users = get_users()
    for user in users:
        if user['login'] == login:
            quota = user.get('quota', '')
            if quota == '':
                return None
            try:
                return int(quota)
            except (ValueError, TypeError):
                return None
    return None

def get_user_used_space(login):
    user_path = os.path.join(CONFIG['UPLOAD_FOLDER'], login)
    if not os.path.exists(user_path):
        return 0
    total_size = 0
    for dirpath, dirnames, filenames in os.walk(user_path):
        for filename in filenames:
            filepath = os.path.join(dirpath, filename)
            total_size += os.path.getsize(filepath)
    return total_size

def format_size(size_bytes):
    if size_bytes is None:
        return "∞"
    if size_bytes < 1024:
        return f"{size_bytes} Б"
    elif size_bytes < 1024 * 1024:
        return f"{size_bytes / 1024:.1f} КБ"
    elif size_bytes < 1024 * 1024 * 1024:
        return f"{size_bytes / (1024 * 1024):.1f} МБ"
    else:
        return f"{size_bytes / (1024 * 1024 * 1024):.2f} ГБ"

def check_user_quota(login, additional_size):
    quota = get_user_quota(login)
    if quota is None:
        return True, 0
    used = get_user_used_space(login)
    if used + additional_size <= quota:
        return True, quota - (used + additional_size)
    else:
        return False, quota - used

def update_user_password(login, new_password):
    users = get_users()
    for user in users:
        if user['login'] == login:
            user['password'] = new_password
            save_users(users)
            return True
    return False

def verify_user(login, password):
    users = get_users()
    return next((u for u in users if u['login'] == login and u['password'] == password), None)

# --- [BLOCK: FILENAME DATABASE HELPERS] ---
FILENAMES_FILE = os.path.join(BASE_DIR, 'filenames.json')
FOLDERNAMES_FILE = os.path.join(BASE_DIR, 'foldernames.json')

def get_filenames_db():
    if not os.path.exists(FILENAMES_FILE):
        return {}
    try:
        with open(FILENAMES_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Ошибка чтения filenames.json: {e}")
        return {}

def save_filenames_db(data):
    with open(FILENAMES_FILE, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def get_foldernames_db():
    if not os.path.exists(FOLDERNAMES_FILE):
        return {}
    try:
        with open(FOLDERNAMES_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Ошибка чтения foldernames.json: {e}")
        return {}

def save_foldernames_db(data):
    with open(FOLDERNAMES_FILE, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def add_folder_mapping(latin_name, original_name):
    db = get_foldernames_db()
    db[latin_name] = original_name
    save_foldernames_db(db)
    return latin_name

def get_original_foldername(latin_name):
    db = get_foldernames_db()
    return db.get(latin_name, latin_name)

def update_folder_mapping(old_latin_name, new_latin_name, original_name):
    db = get_foldernames_db()
    if old_latin_name in db:
        del db[old_latin_name]
    db[new_latin_name] = original_name
    save_foldernames_db(db)

def delete_folder_mapping(latin_name):
    db = get_foldernames_db()
    if latin_name in db:
        del db[latin_name]
        save_foldernames_db(db)

def add_filename_mapping(latin_name, original_name):
    db = get_filenames_db()
    db[latin_name] = original_name
    save_filenames_db(db)
    return latin_name

def get_original_filename(latin_name):
    db = get_filenames_db()
    return db.get(latin_name, latin_name)

def update_filename_mapping(old_latin_name, new_latin_name, original_name):
    db = get_filenames_db()
    if old_latin_name in db:
        del db[old_latin_name]
    db[new_latin_name] = original_name
    save_filenames_db(db)

def delete_filename_mapping(latin_name):
    db = get_filenames_db()
    if latin_name in db:
        del db[latin_name]
        save_filenames_db(db)

# --- [BLOCK: SHARE DB HELPERS] ---
SHARED_FOLDERS_FILE = os.path.join(BASE_DIR, 'shared_folders.json')

def get_shared_folders():
    if not os.path.exists(SHARED_FOLDERS_FILE):
        return {}
    try:
        with open(SHARED_FOLDERS_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"Ошибка чтения shared_folders.json: {e}")
        return {}

def save_shared_folders(data):
    with open(SHARED_FOLDERS_FILE, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def share_folder(folder_path, folder_name, owner):
    shared = get_shared_folders()
    for token, data in shared.items():
        if data.get('path') == folder_path and data.get('type') == 'folder':
            return token
    token = str(uuid.uuid4())[:8]
    shared[token] = {
        'path': folder_path,
        'name': folder_name,
        'owner': owner,
        'type': 'folder',
        'created': datetime.now().isoformat()
    }
    save_shared_folders(shared)
    return token

def unshare_folder(token):
    shared = get_shared_folders()
    if token in shared:
        del shared[token]
        save_shared_folders(shared)
        return True
    return False

def is_folder_shared(folder_path):
    shared = get_shared_folders()
    for token, data in shared.items():
        if data.get('path') == folder_path and data.get('type') == 'folder':
            return token
    return None

def get_shared_files():
    if not os.path.exists(CONFIG['SHARES_FILE']): return {}
    try:
        with open(CONFIG['SHARES_FILE'], 'r', encoding='utf-8') as f:
            d = json.load(f)
            return d if isinstance(d, dict) else {}
    except Exception as e:
        print(f"Ошибка чтения shares.json: {e}")
        return {}

def save_shared_files(data):
    with open(CONFIG['SHARES_FILE'], 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def share_file(file_path, file_name, owner):
    shared = get_shared_files()
    token = str(uuid.uuid4())[:8]
    shared[token] = {
        'path': file_path,
        'name': file_name,
        'owner': owner,
        'type': 'file',
        'created': datetime.now().isoformat()
    }
    save_shared_files(shared)
    return token

def unshare_file(token):
    shared = get_shared_files()
    if token in shared:
        del shared[token]
        save_shared_files(shared)
        return True
    return False

def is_file_shared(file_path):
    shared = get_shared_files()
    for token, data in shared.items():
        if data.get('path') == file_path and data.get('type') == 'file':
            return token
    return None

def is_system_folder(folder_name):
    return folder_name.startswith('INPUT_')

# --- [BLOCK: STATISTICS FUNCTIONS] ---
def get_stats(base_path, rel_path=''):
    current_dir = os.path.join(base_path, rel_path) if rel_path else base_path
    files_count = 0
    folders_count = 0
    total_size = 0
    
    if not os.path.exists(current_dir):
        return 0, 0, 0
    
    for root, dirs, files in os.walk(current_dir):
        for dir_name in dirs:
            if not is_system_folder(dir_name):
                folders_count += 1
        for file in files:
            filepath = os.path.join(root, file)
            try:
                total_size += os.path.getsize(filepath)
                files_count += 1
            except OSError:
                pass
    
    return files_count, folders_count, total_size

# --- [BLOCK: TRANSLITERATION FUNCTION] ---
def transliterate(text):
    cyrillic_map = {
        'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
        'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm',
        'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
        'ф': 'f', 'х': 'kh', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'sch',
        'ъ': '', 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
        'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
        'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'Y', 'К': 'K', 'Л': 'L', 'М': 'M',
        'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
        'Ф': 'F', 'Х': 'Kh', 'Ц': 'Ts', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sch',
        'Ъ': '', 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
    }
    result = []
    for char in text:
        if char in cyrillic_map:
            result.append(cyrillic_map[char])
        else:
            result.append(char)
    translit_name = ''.join(result)
    translit_name = re.sub(r'[^\w\-_\.]', '_', translit_name)
    return translit_name

def secure_folder_name(original_name):
    latin_name = transliterate(original_name)
    return secure_filename(latin_name)

def secure_filename_with_translit(filename):
    name, ext = os.path.splitext(filename)
    translit_name = transliterate(name)
    return secure_filename(translit_name) + ext

# --- [BLOCK: UI HTML] ---
INDEX_HTML = """
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes, viewport-fit=cover">
    <title>Файловый менеджер</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        :root { --sw: 300px; }
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: sans-serif; height: 100vh; display: flex; flex-direction: column; overflow: hidden; background: #fff; }
        header { background: #222; color: #fff; padding: 10px 20px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; }
        .header-left { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
        .space-info { font-size: 14px; color: #aaa; }
        .space-info span { color: #fff; font-weight: bold; margin-left: 5px; }
        .user-menu { cursor: pointer; padding: 5px 10px; border-radius: 5px; transition: background 0.3s; display: flex; align-items: center; gap: 10px; }
        .user-menu:hover { background: #444; }
        .user-menu a { color: orange; text-decoration: none; }
        .user-menu a:hover { text-decoration: underline; }
        .wrapper { display: flex; flex: 1; overflow: hidden; }
        #left { width: var(--sw); background: #f4f4f4; border-right: 1px solid #ccc; overflow-y: auto; padding: 15px; display: flex; flex-direction: column; }
        .search-box { margin-bottom: 15px; position: sticky; top: 0; background: #f4f4f4; padding-bottom: 10px; z-index: 5; }
        .search-box input { width: 100%; padding: 8px 12px; border: 1px solid #ccc; border-radius: 5px; font-size: 14px; }
        .breadcrumb { margin-bottom: 15px; font-size: 14px; word-break: break-all; }
        .breadcrumb a { color: #007bff; text-decoration: none; cursor: pointer; }
        .breadcrumb a:hover { text-decoration: underline; }
        .stats-info {
            margin-top: 15px;
            padding: 10px;
            background: #e8e8e8;
            border-radius: 8px;
            font-size: 12px;
            border-top: 1px solid #ccc;
        }
        .stats-info p {
            margin: 5px 0;
        }
        .folder-item { 
            display: inline-flex; 
            flex-direction: column; 
            align-items: center; 
            padding: 10px; 
            margin: 5px; 
            cursor: pointer; 
            border-radius: 5px; 
            transition: background 0.3s; 
            text-align: center; 
            width: 80px;
            position: relative;
        }
        .folder-item:hover { background: #e0e0e0; }
        .folder-icon-wrapper {
            position: relative;
            display: inline-block;
        }
        .folder-icon { font-size: 48px; }
        .share-badge {
            position: absolute;
            bottom: -5px;
            right: -5px;
            background: #ff4444;
            color: white;
            border-radius: 50%;
            width: 18px;
            height: 18px;
            font-size: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 2px solid white;
        }
        .folder-name { margin-top: 5px; font-size: 12px; word-break: break-all; max-width: 70px; text-align: center; }
        .folder-actions { display: flex; gap: 5px; margin-top: 5px; justify-content: center; }
        .folder-actions button { background: none; border: none; cursor: pointer; font-size: 12px; padding: 2px 5px; border-radius: 3px; }
        .folder-actions button:hover { background: #ccc; }
        .file-item { position: relative; margin-bottom: 20px; text-align: center; border-bottom: 1px solid #eee; padding-bottom: 15px; }
        .file-item img, .file-item video { max-width: 100%; border-radius: 5px; cursor: pointer; background: #000; max-height: 200px; }
        .file-actions { position: absolute; top: 5px; right: 5px; display: none; gap: 5px; background: rgba(0,0,0,0.7); padding: 5px; border-radius: 5px; z-index: 10; }
        .file-item:hover .file-actions { display: flex; }
        .file-actions button { background: none; border: none; color: white; cursor: pointer; font-size: 14px; padding: 5px; border-radius: 3px; }
        .file-actions button:hover { background: rgba(255,255,255,0.2); }
        .file-row { display: flex; align-items: center; margin-top: 8px; gap: 8px; justify-content: space-between; }
        .file-link { color: #007bff; text-decoration: none; font-size: 0.9em; flex: 1; word-break: break-all; text-align: left; cursor: pointer; }
        .file-link:hover { text-decoration: underline; }
        .file-buttons { display: flex; gap: 5px; }
        .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 3000; align-items: center; justify-content: center; }
        .modal-content { background: white; padding: 20px; border-radius: 10px; width: 350px; text-align: center; max-height: 80vh; overflow-y: auto; }
        .modal-content input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-radius: 5px; }
        .folder-list { max-height: 300px; overflow-y: auto; margin: 10px 0; text-align: left; }
        .folder-list-item { padding: 10px; margin: 5px 0; cursor: pointer; border-radius: 5px; display: flex; align-items: center; gap: 10px; }
        .folder-list-item:hover { background: #f0f0f0; }
        .folder-list-item.selected { background: #007bff; color: white; }
        .modal-buttons { display: flex; gap: 10px; margin-top: 20px; }
        .modal-buttons button { flex: 1; padding: 10px; border: none; border-radius: 5px; cursor: pointer; font-size: 14px; }
        .btn-success { background: #28a745; color: white; }
        .btn-success:hover { background: #218838; }
        .btn-danger { background: #dc3545; color: white; }
        .btn-danger:hover { background: #c82333; }
        .create-folder-btn { background: #28a745; color: white; border: none; padding: 5px 10px; border-radius: 5px; cursor: pointer; margin-bottom: 10px; font-size: 12px; }
        .create-folder-btn:hover { background: #218838; }
        #right { flex: 1; padding: 25px; display: flex; flex-direction: column; align-items: center; overflow-y: auto; }
        #drop-zone { width: 90%; max-width: 500px; height: 150px; border: 2px dashed #007bff; border-radius: 15px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; cursor: pointer; color: #007bff; transition: all 0.3s ease; margin-bottom: 20px; background: #fafafa; }
        #drop-zone.dragover { background: #e3f2fd; border-color: #0056b3; transform: scale(1.02); }
        #paste-preview { width: 90%; max-width: 500px; display: none; flex-direction: column; align-items: center; gap: 15px; padding: 20px; border: 1px solid #ddd; border-radius: 10px; background: #f9f9f9; }
        #paste-preview img { max-width: 100%; max-height: 300px; border-radius: 5px; }
        #quota-error { color: #dc3545; font-size: 14px; margin-top: 10px; display: none; text-align: center; width: 90%; max-width: 500px; }
        .separator { margin: 10px 0; border-top: 1px solid #ccc; }
        .error-message { color: #dc3545; font-size: 12px; margin-top: 5px; display: none; }
        .success-message { color: #28a745; font-size: 12px; margin-top: 5px; display: none; }
        #gallery-overlay { 
            display: none; 
            position: fixed; 
            top: 0; 
            left: 0; 
            width: 100%; 
            height: 100%; 
            background: rgba(0,0,0,0.95); 
            z-index: 2000; 
            align-items: center; 
            justify-content: center;
        }
        #gallery-content {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 100%;
            position: relative;
        }
        .gallery-nav {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            font-size: 50px;
            color: white;
            cursor: pointer;
            background: rgba(0,0,0,0.5);
            width: 60px;
            height: 80px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 10px;
            transition: background 0.3s;
            z-index: 2002;
        }
        .gallery-nav:hover {
            background: rgba(0,0,0,0.8);
        }
        .gallery-nav-prev {
            left: 20px;
        }
        .gallery-nav-next {
            right: 20px;
        }
        .gallery-media {
            display: flex;
            align-items: center;
            justify-content: center;
            max-width: 90vw;
            max-height: 80vh;
        }
        .gallery-media img {
            max-width: 100%;
            max-height: 80vh;
            object-fit: contain;
            cursor: pointer;
            transition: transform 0.2s ease;
        }
        .gallery-media video {
            max-width: 95vw;
            max-height: 80vh;
            cursor: pointer;
        }
        .gallery-filename {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0,0,0,0.7);
            color: white;
            padding: 8px 16px;
            border-radius: 20px;
            font-size: 14px;
            z-index: 2002;
            white-space: nowrap;
            max-width: 80%;
            overflow-x: auto;
            text-overflow: ellipsis;
        }
        #close-gallery { 
            position: absolute; 
            top: 20px; 
            right: 20px; 
            font-size: 40px; 
            cursor: pointer; 
            color: white; 
            z-index: 2001;
            background: rgba(0,0,0,0.5);
            width: 50px;
            height: 50px;
            border-radius: 25px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background 0.3s;
        }
        #close-gallery:hover {
            background: rgba(0,0,0,0.8);
        }
        hr { margin: 10px 0; }
        
        @media (max-width: 768px) {
            .wrapper { flex-direction: column; }
            #left { width: 100% !important; height: 45%; }
            #resizer { display: none; }
            .gallery-nav { width: 40px; height: 60px; font-size: 30px; }
            .gallery-filename { font-size: 10px; padding: 4px 8px; bottom: 10px; }
        }
    </style>
</head>
<body>
{% if not session.get('logged_in') %}
    <div style="max-width: 320px; margin: 100px auto; padding: 30px; border: 1px solid #ddd; border-radius: 10px; text-align: center;">
        <h3>Файловый менеджер</h3>
        <form action="/login" method="post">
            <input type="text" name="login" placeholder="Логин" required style="width:100%; padding:10px; margin-bottom:10px;">
            <input type="password" name="password" placeholder="Пароль" required style="width:100%; padding:10px; margin-bottom:15px;">
            <button type="submit" style="width:100%; padding:10px; background:#222; color:#fff; border:none; cursor:pointer;">Войти</button>
        </form>
    </div>
{% else %}
    <header>
        <div class="header-left">
            <strong>Файловый менеджер</strong>
            <div class="space-info">Всего места: <span id="total-space">{{ total_space }}</span> | Свободно: <span id="free-space">{{ free_space }}</span></div>
        </div>
        <div class="user-menu">
            <span onclick="showChangePasswordModal()">{{ session['user_name'] }} ▼</span>
            <a href="/logout">Выход</a>
        </div>
    </header>
    <div class="wrapper">
        <div id="left">
            <div class="search-box"><input type="text" id="search-input" placeholder="Поиск файлов... (3+ символа)" autocomplete="off"></div>
            <div id="current-path" class="breadcrumb"></div>
            <button class="create-folder-btn" onclick="showCreateFolderModal()">+ Новая папка</button>
            <div id="file-list">Загрузка...</div>
            <div id="stats-info" class="stats-info"></div>
        </div>
        <div id="resizer"></div>
        <div id="right">
            <div id="drop-zone" oncontextmenu="showPasteDialog(event); return false;">Кликните или перетащите файл для загрузки<br><br>Правая кнопка мыши для вставки из буфера</div>
            <div id="quota-error"></div>
            <div id="paste-preview">
                <img id="paste-image" src="" alt="Превью">
                <input type="text" id="paste-filename" placeholder="Введите имя файла (без расширения)" value="image">
                <div style="display: flex; gap: 10px; width: 100%;">
                    <button id="paste-save" style="flex:1; padding:10px; background:#28a745; color:white; border:none; border-radius:5px; cursor:pointer;">Сохранить</button>
                    <button id="paste-cancel" style="flex:1; padding:10px; background:#dc3545; color:white; border:none; border-radius:5px; cursor:pointer;">Отмена</button>
                </div>
            </div>
            <input type="file" id="file-input" style="display:none" multiple>
        </div>
    </div>
    
    <div id="change-password-modal" class="modal">
        <div class="modal-content">
            <h3>Смена пароля</h3>
            <input type="password" id="new-password" placeholder="Новый пароль">
            <input type="password" id="confirm-password" placeholder="Подтверждение">
            <div id="password-error" class="error-message">Пароли не совпадают</div>
            <div id="password-success" class="success-message">Пароль успешно изменен</div>
            <div class="modal-buttons">
                <button id="change-password-save" class="btn-success">Сохранить</button>
                <button id="change-password-cancel" class="btn-danger">Отмена</button>
            </div>
        </div>
    </div>
    
    <div id="create-folder-modal" class="modal">
        <div class="modal-content">
            <h3>Создать папку</h3>
            <input type="text" id="folder-name" placeholder="Имя папки">
            <div class="modal-buttons">
                <button id="create-folder-save" class="btn-success">Создать</button>
                <button id="create-folder-cancel" class="btn-danger">Отмена</button>
            </div>
        </div>
    </div>
    
    <div id="rename-folder-modal" class="modal">
        <div class="modal-content">
            <h3>Переименовать папку</h3>
            <input type="text" id="rename-folder-name" placeholder="Новое имя папки">
            <div class="modal-buttons">
                <button id="rename-folder-save" class="btn-success">Сохранить</button>
                <button id="rename-folder-cancel" class="btn-danger">Отмена</button>
            </div>
        </div>
    </div>
    
    <div id="rename-file-modal" class="modal">
        <div class="modal-content">
            <h3>Переименовать файл</h3>
            <input type="text" id="rename-file-name" placeholder="Новое имя файла">
            <div class="modal-buttons">
                <button id="rename-file-save" class="btn-success">Сохранить</button>
                <button id="rename-file-cancel" class="btn-danger">Отмена</button>
            </div>
        </div>
    </div>
    
    <div id="move-file-modal" class="modal">
        <div class="modal-content">
            <h3>Выберите папку для перемещения</h3>
            <div id="folder-list" class="folder-list"></div>
            <div class="modal-buttons">
                <button id="move-file-save" class="btn-success">Перенести</button>
                <button id="move-file-cancel" class="btn-danger">Отмена</button>
            </div>
        </div>
    </div>
    
    <div id="share-modal" class="modal">
        <div class="modal-content">
            <h3>Доступ</h3>
            <label><input type="checkbox" id="share-toggle"> Поделиться</label>
            <div id="share-box" style="display:none; margin-top:10px; background:#eee; padding:10px; font-size:0.8em; word-break:break-all;">
                <span id="share-url"></span><br><br>
                <button id="copy-btn">Копировать</button>
            </div>
            <div style="margin-top:20px;">
                <button onclick="$('.modal').hide()">Отмена</button>
                <button id="share-save" class="btn-success">Сохранить</button>
            </div>
        </div>
    </div>
    
    <div id="confirm-modal" class="modal">
        <div class="modal-content">
            <p id="confirm-message">Удалить файл?</p>
            <div class="modal-buttons">
                <button onclick="$('.modal').hide()">Нет</button>
                <button id="modal-confirm" class="btn-danger">Да</button>
            </div>
        </div>
    </div>
    
    <div id="gallery-overlay">
        <div id="gallery-content"></div>
        <div class="gallery-nav gallery-nav-prev" id="gallery-prev">❮</div>
        <div class="gallery-nav gallery-nav-next" id="gallery-next">❯</div>
        <div id="close-gallery">&times;</div>
    </div>
{% endif %}

<script>
let currentPath = '';
let searchTimeout = null;
let currentFileToRename = null;
let currentFileToMove = null;
let currentFolderToRename = null;
let currentShareItem = null;
let currentShareType = null;
let currentShareToken = null;
let selectedFolderPath = '';
let galleryItems = [];
let currentGalleryIndex = 0;

const loadFiles = (path) => {
    const searchQuery = $('#search-input').val();
    $.get('/files', { path: path, search: searchQuery }, (data) => {
        $('#file-list').html(data.html);
        $('#current-path').html(data.breadcrumb);
        currentPath = data.current_path;
        updateStats();
    }).fail((xhr) => $('#file-list').html("<b style='color:red'>Ошибка сервера: "+xhr.status+"</b>"));
};

const updateStats = () => {
    $.get('/stats', { path: currentPath }, (data) => {
        $('#stats-info').html(`
            <p>📁 Папок: ${data.folders}</p>
            <p>📄 Файлов: ${data.files}</p>
            <p>💾 Общий размер: ${data.size}</p>
        `);
    });
};

$(document).ready(function() {
    {% if session.get('logged_in') %}
    const updateSpaceInfo = () => {
        $.get('/space_info', (data) => {
            $('#total-space').text(data.total_space);
            $('#free-space').text(data.free_space);
        });
    };
    
    $('#search-input').on('input', function() {
        clearTimeout(searchTimeout);
        const query = $(this).val();
        if (query.length >= 3 || query.length === 0) {
            searchTimeout = setTimeout(() => loadFiles(currentPath), 500);
        }
    });
    
    loadFiles('');
    updateSpaceInfo();
    
    // Resizer
    const resizer = document.getElementById('resizer');
    const leftPanel = document.getElementById('left');
    let isResizing = false;
    let startX = 0;
    let startWidth = 0;
    
    function getCookie(name) {
        const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
        return match ? match[2] : null;
    }
    
    const savedWidth = getCookie('sw');
    if (savedWidth) document.documentElement.style.setProperty('--sw', savedWidth + 'px');
    
    if (resizer) {
        resizer.addEventListener('mousedown', function(e) {
            isResizing = true;
            startX = e.clientX;
            startWidth = leftPanel.offsetWidth;
            resizer.classList.add('resizing');
            e.preventDefault();
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
        });
    }
    
    function onMouseMove(e) {
        if (!isResizing) return;
        const dx = e.clientX - startX;
        const newWidth = Math.max(200, Math.min(800, startWidth + dx));
        document.documentElement.style.setProperty('--sw', newWidth + 'px');
        e.preventDefault();
    }
    
    function onMouseUp(e) {
        if (isResizing) {
            isResizing = false;
            if (resizer) resizer.classList.remove('resizing');
            document.cookie = "sw=" + leftPanel.offsetWidth + "; path=/; max-age=31536000";
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
        }
    }
    
    // Drag & drop
    const dropZone = document.getElementById('drop-zone');
    
    function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); }
    
    if (dropZone) {
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            dropZone.addEventListener(eventName, preventDefaults, false);
            document.body.addEventListener(eventName, preventDefaults, false);
        });
        ['dragenter', 'dragover'].forEach(eventName => {
            dropZone.addEventListener(eventName, () => dropZone.classList.add('dragover'), false);
        });
        ['dragleave', 'drop'].forEach(eventName => {
            dropZone.addEventListener(eventName, () => dropZone.classList.remove('dragover'), false);
        });
        dropZone.addEventListener('drop', handleDrop, false);
        $('#drop-zone').on('click', () => $('#file-input').click());
    }
    
    function handleDrop(e) {
        const files = e.dataTransfer.files;
        if (files.length > 0) uploadFiles(files);
    }
    
    function uploadFiles(files) {
        const fd = new FormData();
        for (let i = 0; i < files.length; i++) fd.append('files', files[i]);
        fd.append('current_path', currentPath);
        $('#quota-error').hide().text('');
        $.ajax({
            url: '/upload', type: 'POST', data: fd, processData: false, contentType: false,
            success: function(response) {
                if (response.error) $('#quota-error').text(response.error).show();
                else { loadFiles(currentPath); updateSpaceInfo(); }
            },
            error: function(xhr) {
                if (xhr.responseJSON && xhr.responseJSON.error) $('#quota-error').text(xhr.responseJSON.error).show();
                else alert('Ошибка при загрузке файлов');
            }
        });
    }
    
    $('#file-input').on('change', function() { if (this.files.length > 0) uploadFiles(this.files); });
    
    // Folder management
    window.showCreateFolderModal = function() { $('#folder-name').val(''); $('#create-folder-modal').css('display', 'flex'); };
    $('#create-folder-save').on('click', function() {
        const folderName = $('#folder-name').val().trim();
        if (!folderName) { alert('Введите имя папки'); return; }
        $.ajax({
            url: '/create_folder', type: 'POST', data: { folder_name: folderName, current_path: currentPath },
            success: function(response) {
                if (response.success) { $('#create-folder-modal').hide(); loadFiles(currentPath); }
                else alert('Ошибка: ' + response.error);
            },
            error: function(xhr) { alert('Ошибка: ' + (xhr.responseJSON?.error || 'Неизвестная ошибка')); }
        });
    });
    $('#create-folder-cancel').on('click', () => $('#create-folder-modal').hide());
    
    window.showRenameFolderModal = function(folderPath, folderName) {
        currentFolderToRename = folderPath;
        $('#rename-folder-name').val(folderName);
        $('#rename-folder-modal').css('display', 'flex');
    };
    $('#rename-folder-save').on('click', function() {
        const newName = $('#rename-folder-name').val().trim();
        if (!newName) { alert('Введите новое имя папки'); return; }
        $.ajax({
            url: '/rename_folder', type: 'POST', data: { old_path: currentFolderToRename, new_name: newName },
            success: function(response) {
                if (response.success) { $('#rename-folder-modal').hide(); loadFiles(currentPath); }
                else alert('Ошибка: ' + response.error);
            }
        });
    });
    $('#rename-folder-cancel').on('click', () => $('#rename-folder-modal').hide());
    
    window.deleteFolder = function(folderPath, folderName) {
        $('#confirm-message').text('Удалить папку "' + folderName + '" и всё её содержимое?');
        window.itemToDelete = { type: 'folder', path: folderPath };
        $('#confirm-modal').css('display', 'flex');
    };
    
    // Share functions
    window.showShareModal = function(itemPath, itemName, type, token) {
        currentShareItem = itemPath;
        currentShareType = type;
        currentShareToken = token;
        $('#share-toggle').prop('checked', !!token);
        if(token) {
            $('#share-url').text(window.location.origin + '/s/' + token);
            $('#share-box').show();
        } else {
            $('#share-box').hide();
        }
        $('#share-modal').css('display', 'flex');
    };
    
    $('#share-save').on('click', () => {
        const isActive = $('#share-toggle').is(':checked');
        $.ajax({
            url: '/share_item', type: 'POST', data: { path: currentShareItem, type: currentShareType, active: isActive },
            success: function(response) {
                if (response.success) { $('#share-modal').hide(); loadFiles(currentPath); }
                else alert('Ошибка: ' + response.error);
            },
            error: function() { alert('Ошибка при сохранении'); }
        });
    });
    
    $('#copy-btn').on('click', function() {
        const copyText = $('#share-url').text();
        navigator.clipboard.writeText(copyText).then(function() {
            alert("Ссылка скопирована!");
        }).catch(function() {
            const textarea = document.createElement('textarea');
            textarea.value = copyText;
            document.body.appendChild(textarea);
            textarea.select();
            document.execCommand('copy');
            document.body.removeChild(textarea);
            alert("Ссылка скопирована!");
        });
    });
    
    // File management
    window.showRenameFileModal = function(filePath, fileName) {
        currentFileToRename = filePath;
        $('#rename-file-name').val(fileName);
        $('#rename-file-modal').css('display', 'flex');
    };
    $('#rename-file-save').on('click', function() {
        const newName = $('#rename-file-name').val().trim();
        if (!newName) { alert('Введите новое имя файла'); return; }
        $.ajax({
            url: '/rename_file', type: 'POST', data: { old_path: currentFileToRename, new_name: newName },
            success: function(response) {
                if (response.success) { $('#rename-file-modal').hide(); loadFiles(currentPath); }
                else alert('Ошибка: ' + response.error);
            }
        });
    });
    $('#rename-file-cancel').on('click', () => $('#rename-file-modal').hide());
    
    window.showMoveFileModal = function(filePath, fileName) {
        currentFileToMove = filePath;
        selectedFolderPath = '';
        $.ajax({
            url: '/get_folders', type: 'GET',
            success: function(response) {
                let html = '<div class="folder-list-item" data-path="">📁 Корневая папка</div>';
                response.folders.forEach(folder => {
                    html += '<div class="folder-list-item" data-path="' + folder.path + '">📁 ' + folder.display_name + '</div>';
                });
                $('#folder-list').html(html);
                $('.folder-list-item').on('click', function() {
                    $('.folder-list-item').removeClass('selected');
                    $(this).addClass('selected');
                    selectedFolderPath = $(this).data('path');
                });
                $('#move-file-modal').css('display', 'flex');
            }
        });
    };
    $('#move-file-save').on('click', function() {
        if (!selectedFolderPath && selectedFolderPath !== '') { alert('Выберите папку для перемещения'); return; }
        $.ajax({
            url: '/move_file', type: 'POST', data: { file_path: currentFileToMove, target_folder: selectedFolderPath },
            success: function(response) {
                if (response.success) { $('#move-file-modal').hide(); loadFiles(currentPath); }
                else alert('Ошибка: ' + response.error);
            }
        });
    });
    $('#move-file-cancel').on('click', () => $('#move-file-modal').hide());
    
    window.deleteFile = function(filePath, fileName) {
        $('#confirm-message').text('Удалить файл "' + fileName + '"?');
        window.itemToDelete = { type: 'file', path: filePath };
        $('#confirm-modal').css('display', 'flex');
    };
    
    $('#modal-confirm').on('click', () => {
        if (window.itemToDelete) {
            $.post('/delete', { path: window.itemToDelete.path, type: window.itemToDelete.type }, () => {
                $('.modal').hide();
                loadFiles(currentPath);
                updateSpaceInfo();
                window.itemToDelete = null;
            });
        }
    });
    
    // Paste from clipboard
    window.showPasteDialog = function(e) {
        e.preventDefault();
        navigator.clipboard.read().then(clipboardItems => {
            for (const item of clipboardItems) {
                if (item.types.includes('image/png') || item.types.includes('image/jpeg') || item.types.includes('image/gif')) {
                    item.getType('image/png').then(blob => displayPastePreview(blob))
                        .catch(() => item.getType('image/jpeg').then(blob => displayPastePreview(blob)))
                        .catch(() => item.getType('image/gif').then(blob => displayPastePreview(blob)))
                        .catch(() => alert('Не удалось прочитать изображение'));
                    return;
                }
            }
            alert('В буфере обмена нет изображения');
        }).catch(() => alert('Не удалось получить доступ к буферу обмена'));
    };
    
    function displayPastePreview(blob) {
        const reader = new FileReader();
        reader.onloadend = function() {
            $('#paste-image').attr('src', reader.result);
            $('#paste-preview').css('display', 'flex');
            const now = new Date();
            const defaultName = 'image_' + now.getFullYear() + String(now.getMonth() + 1).padStart(2, '0') + String(now.getDate()).padStart(2, '0');
            $('#paste-filename').val(defaultName);
            window.pasteBlob = blob;
        };
        reader.readAsDataURL(blob);
    }
    
    $('#paste-save').on('click', function() {
        const filename = $('#paste-filename').val().trim();
        if (!filename) { alert('Введите имя файла'); return; }
        if (window.pasteBlob) {
            let extension = 'png';
            if (window.pasteBlob.type === 'image/jpeg') extension = 'jpg';
            else if (window.pasteBlob.type === 'image/gif') extension = 'gif';
            const file = new File([window.pasteBlob], filename + '.' + extension, { type: window.pasteBlob.type });
            const fd = new FormData();
            fd.append('files', file);
            fd.append('current_path', currentPath);
            $.ajax({
                url: '/upload', type: 'POST', data: fd, processData: false, contentType: false,
                success: function() {
                    $('#paste-preview').hide();
                    window.pasteBlob = null;
                    loadFiles(currentPath);
                    updateSpaceInfo();
                }
            });
        }
    });
    
    $('#paste-cancel').on('click', function() {
        $('#paste-preview').hide();
        window.pasteBlob = null;
    });
    
    // Gallery with navigation
    function openGallery(items, index) {
        galleryItems = items;
        currentGalleryIndex = index;
        showGalleryItem();
        $('#gallery-overlay').css('display', 'flex');
    }
    
    function showGalleryItem() {
        const item = galleryItems[currentGalleryIndex];
        if (!item) return;
        
        const isVideo = item.type === 'video';
        let mediaHtml;
        if (isVideo) {
            mediaHtml = '<video src="' + item.url + '" controls autoplay class="gallery-media-video"></video>';
        } else {
            mediaHtml = '<img src="' + item.url + '" class="gallery-media-img">';
        }
        
        const html = `
            <div class="gallery-media">
                ${mediaHtml}
            </div>
            <div class="gallery-filename">${item.name}</div>
        `;
        $('#gallery-content').html(html);
        
        if (!isVideo) {
            const img = $('#gallery-content .gallery-media-img');
            let zoomed = false;
            img.off('click').on('click', function(e) {
                e.stopPropagation();
                if (!zoomed) {
                    $(this).css({
                        'transform': 'scale(2)',
                        'cursor': 'zoom-out'
                    });
                    zoomed = true;
                } else {
                    $(this).css({
                        'transform': 'scale(1)',
                        'cursor': 'zoom-in'
                    });
                    zoomed = false;
                }
            });
        }
        
        $('#gallery-prev').css('opacity', currentGalleryIndex === 0 ? '0.3' : '1');
        $('#gallery-next').css('opacity', currentGalleryIndex === galleryItems.length - 1 ? '0.3' : '1');
    }
    
    function nextGalleryItem() {
        if (currentGalleryIndex < galleryItems.length - 1) {
            currentGalleryIndex++;
            showGalleryItem();
        }
    }
    
    function prevGalleryItem() {
        if (currentGalleryIndex > 0) {
            currentGalleryIndex--;
            showGalleryItem();
        }
    }
    
    // Собираем все медиа-файлы из текущей папки
    function collectGalleryItems() {
        const items = [];
        $('.file-item .gallery-trigger').each(function() {
            const src = $(this).attr('src');
            const isVideo = $(this).prop('tagName') === 'VIDEO';
            const fileName = $(this).closest('.file-item').find('.file-link').text();
            items.push({
                url: src,
                type: isVideo ? 'video' : 'image',
                name: fileName
            });
        });
        return items;
    }
    
    $(document).on('click', '.gallery-trigger', function() {
        const items = collectGalleryItems();
        const currentSrc = $(this).attr('src');
        const index = items.findIndex(item => item.url === currentSrc);
        openGallery(items, index);
    });
    
    $('#gallery-next').on('click', function(e) {
        e.stopPropagation();
        nextGalleryItem();
    });
    
    $('#gallery-prev').on('click', function(e) {
        e.stopPropagation();
        prevGalleryItem();
    });
    
    $('#close-gallery').on('click', function(e) {
        e.stopPropagation();
        $('#gallery-overlay').hide();
        $('#gallery-content').empty();
    });
    
    $('#gallery-overlay').on('click', function(e) {
        if (e.target === this) {
            $('#gallery-overlay').hide();
            $('#gallery-content').empty();
        }
    });
    
    // Keyboard navigation
    $(document).on('keydown', function(e) {
        if ($('#gallery-overlay').is(':visible')) {
            if (e.key === 'ArrowLeft') {
                prevGalleryItem();
            } else if (e.key === 'ArrowRight') {
                nextGalleryItem();
            } else if (e.key === 'Escape') {
                $('#gallery-overlay').hide();
                $('#gallery-content').empty();
            }
        }
    });
    
    // Change password
    window.showChangePasswordModal = function() {
        $('#new-password').val('');
        $('#confirm-password').val('');
        $('#password-error').hide();
        $('#password-success').hide();
        $('#change-password-modal').css('display', 'flex');
    };
    $('#change-password-save').on('click', function() {
        const newPassword = $('#new-password').val();
        const confirmPassword = $('#confirm-password').val();
        if (newPassword !== confirmPassword) { $('#password-error').show(); return; }
        if (newPassword.length < 3) { alert('Пароль должен содержать минимум 3 символа'); return; }
        $.ajax({
            url: '/change_password', type: 'POST', data: { new_password: newPassword, confirm_password: confirmPassword },
            success: function(response) {
                if (response.success) {
                    $('#password-success').show();
                    setTimeout(() => $('#change-password-modal').hide(), 1500);
                } else alert('Ошибка: ' + response.error);
            }
        });
    });
    $('#change-password-cancel').on('click', () => $('#change-password-modal').hide());
    {% endif %}
});
</script>
</body>
</html>
"""

# --- [BLOCK: ROUTES] ---
@app.route('/')
def index():
    if session.get('logged_in'):
        used = get_user_used_space(session['user_login'])
        quota = get_user_quota(session['user_login'])
        total_space = format_size(quota) if quota is not None else "∞"
        free_space = format_size(quota - used) if quota is not None else "∞"
        return render_template_string(INDEX_HTML, total_space=total_space, free_space=free_space)
    return render_template_string(INDEX_HTML)

@app.route('/stats')
def stats():
    if not session.get('logged_in'):
        return jsonify({'files': 0, 'folders': 0, 'size': '0 Б'}), 401
    
    u = session['user_login']
    rel_path = request.args.get('path', '')
    base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
    
    files_count, folders_count, total_size = get_stats(base_path, rel_path)
    
    return jsonify({
        'files': files_count,
        'folders': folders_count,
        'size': format_size(total_size)
    })

@app.route('/files')
def list_files():
    try:
        if not session.get('logged_in'):
            return jsonify({'html': '', 'breadcrumb': '', 'current_path': ''}), 401
        
        u = session['user_login']
        rel_path = request.args.get('path', '')
        search_query = request.args.get('search', '')
        
        base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
        current_dir = os.path.join(base_path, rel_path) if rel_path else base_path
        
        if not os.path.abspath(current_dir).startswith(os.path.abspath(base_path)):
            return jsonify({'html': 'Доступ запрещен', 'breadcrumb': '', 'current_path': ''}), 403
        
        filenames_db = get_filenames_db()
        foldernames_db = get_foldernames_db()
        
        breadcrumb = '<a onclick="loadFiles(\'\')">Главная</a>'
        if rel_path:
            parts = rel_path.split('/')
            current = ''
            for i, part in enumerate(parts):
                display_part = foldernames_db.get(part, part)
                if i < len(parts) - 1:
                    current += part + '/'
                    breadcrumb += f' / <a onclick="loadFiles(\'{current}\')">{display_part}</a>'
                else:
                    breadcrumb += f' / <span>{display_part}</span>'
        
        html = ''
        
        # Показываем папки
        if not search_query or len(search_query) < 3:
            items = []
            if os.path.exists(current_dir):
                for item in os.listdir(current_dir):
                    item_path = os.path.join(current_dir, item)
                    if os.path.isdir(item_path) and not is_system_folder(item):
                        rel_item_path = os.path.relpath(item_path, base_path)
                        display_name = foldernames_db.get(item, item)
                        shared_token = is_folder_shared(os.path.join(u, rel_item_path))
                        items.append({
                            'name': item,
                            'display_name': display_name,
                            'path': rel_item_path,
                            'shared_token': shared_token
                        })
            items.sort(key=lambda x: x['display_name'].lower())
            if items:
                html += '<div style="display: flex; flex-wrap: wrap; gap: 10px;">'
                for item in items:
                    share_badge = '<div class="share-badge">🔗</div>' if item['shared_token'] else ''
                    html += f'''
                    <div class="folder-item">
                        <div class="folder-icon-wrapper">
                            <div class="folder-icon" onclick="loadFiles('{item['path']}')">📁</div>
                            {share_badge}
                        </div>
                        <div class="folder-name">{item['display_name']}</div>
                        <div class="folder-actions">
                            <button onclick="event.stopPropagation(); showShareModal('{item['path']}', '{item['display_name']}', 'folder', '{item['shared_token'] or ''}')">🔗</button>
                            <button onclick="event.stopPropagation(); showRenameFolderModal('{item['path']}', '{item['display_name']}')">✏️</button>
                            <button onclick="event.stopPropagation(); deleteFolder('{item['path']}', '{item['display_name']}')">🗑️</button>
                        </div>
                    </div>
                    '''
                html += '</div><div class="separator"></div>'
        
        # Получаем файлы
        files_list = []
        
        if search_query and len(search_query) >= 3:
            search_lower = search_query.lower()
            for root, dirs, files in os.walk(current_dir):
                for file in files:
                    original_name = filenames_db.get(file, file)
                    if search_lower in original_name.lower() or search_lower in file.lower():
                        rel_file_path = os.path.relpath(os.path.join(root, file), base_path)
                        shared_token = is_file_shared(os.path.join(u, rel_file_path))
                        files_list.append({
                            'name': file,
                            'display_name': original_name,
                            'path': rel_file_path,
                            'shared_token': shared_token
                        })
            files_list.sort(key=lambda x: x['display_name'].lower())
        else:
            if not rel_path and os.path.exists(base_path):
                for item in os.listdir(base_path):
                    item_path = os.path.join(base_path, item)
                    if os.path.isdir(item_path) and is_system_folder(item):
                        for file in os.listdir(item_path):
                            file_path = os.path.join(item_path, file)
                            if os.path.isfile(file_path):
                                rel_file_path = os.path.relpath(file_path, base_path)
                                original_name = filenames_db.get(file, file)
                                shared_token = is_file_shared(os.path.join(u, rel_file_path))
                                files_list.append({
                                    'name': file,
                                    'display_name': original_name,
                                    'path': rel_file_path,
                                    'shared_token': shared_token
                                })
            if os.path.exists(current_dir):
                for item in os.listdir(current_dir):
                    item_path = os.path.join(current_dir, item)
                    if os.path.isfile(item_path):
                        rel_item_path = os.path.relpath(item_path, base_path)
                        original_name = filenames_db.get(item, item)
                        shared_token = is_file_shared(os.path.join(u, rel_item_path))
                        files_list.append({
                            'name': item,
                            'display_name': original_name,
                            'path': rel_item_path,
                            'shared_token': shared_token
                        })
            files_list.sort(key=lambda x: x['display_name'].lower())
        
        # Отображаем файлы
        for file_info in files_list:
            n = file_info['name']
            display_name = file_info['display_name']
            rel = file_info['path']
            url = f"/download/{u}/{rel}"
            shared_token = file_info['shared_token']
            display_name_js = display_name.replace("'", "\\'").replace('"', '\\"')
            
            file_ext = n.lower().split('.')[-1] if '.' in n else ''
            is_image = file_ext in ['jpg', 'jpeg', 'png', 'gif', 'webp']
            is_video = file_ext in ['mp4', 'webm', 'avi', 'mov']
            is_pdf = file_ext == 'pdf'
            is_media = is_image or is_video or is_pdf
            
            btns = f'''
            <div class="file-buttons">
                <span class="btn-share" onclick="showShareModal('{rel}', '{display_name_js}', 'file', '{shared_token or ''}')" style="cursor:pointer">🔗</span>
                <span onclick="deleteFile('{rel}', '{display_name_js}')" style="cursor:pointer">🗑</span>
            </div>
            '''
            file_actions = f'''
            <div class="file-actions">
                <button onclick="showRenameFileModal('{rel}', '{display_name_js}')">✏️</button>
                <button onclick="showMoveFileModal('{rel}', '{display_name_js}')">📁</button>
            </div>
            '''
            
            if is_media:
                if is_video:
                    tag = f'<video class="gallery-trigger" src="{url}" muted style="max-width:100%; max-height:200px;"></video>'
                elif is_pdf:
                    # PDF - открываем в новой вкладке
                    tag = f'<div class="pdf-preview" style="cursor:pointer; text-align:center; padding:20px; background:#f5f5f5; border-radius:5px;" onclick="window.open(\'{url}?view=1\', \'_blank\')">📄 PDF документ<br><span style="font-size:12px; color:#666;">Кликните для просмотра</span></div>'
                else:
                    tag = f'<img class="gallery-trigger" src="{url}" style="max-width:100%; max-height:200px;">'
                html += f'<div class="file-item">{file_actions}{tag}<div class="file-row"><a href="{url}" download class="file-link">{display_name}</a>{btns}</div></div><hr>'
            else:
                html += f'<div class="file-item">{file_actions}<div class="file-row"><a href="{url}" download class="file-link">📄 {display_name}</a>{btns}</div></div><hr>'
        
        if not html:
            html = "Папка пуста"
        
        return jsonify({'html': html, 'breadcrumb': breadcrumb, 'current_path': rel_path})
    except Exception as e:
        print(f"Ошибка в list_files: {e}")
        traceback.print_exc()
        return jsonify({'html': str(e), 'breadcrumb': '', 'current_path': ''}), 500

@app.route('/share_item', methods=['POST'])
def share_item():
    try:
        if not session.get('logged_in'):
            return jsonify({'success': False, 'error': 'Не авторизован'}), 401
        
        path = request.form.get('path')
        item_type = request.form.get('type')
        active = request.form.get('active') == 'true'
        
        u = session['user_login']
        full_path = os.path.join(u, path)
        
        if item_type == 'folder':
            if active:
                folder_name = os.path.basename(path)
                token = share_folder(full_path, folder_name, u)
                return jsonify({'success': True, 'token': token})
            else:
                shared = get_shared_folders()
                for token, data in shared.items():
                    if data.get('path') == full_path:
                        unshare_folder(token)
                        return jsonify({'success': True})
                return jsonify({'success': True})
        elif item_type == 'file':
            if active:
                token = share_file(full_path, os.path.basename(path), u)
                return jsonify({'success': True, 'token': token})
            else:
                shared = get_shared_files()
                for token, data in shared.items():
                    if data.get('path') == full_path:
                        unshare_file(token)
                        return jsonify({'success': True})
                return jsonify({'success': True})
        
        return jsonify({'success': False, 'error': 'Неизвестный тип'})
    except Exception as e:
        print(f"Ошибка в share_item: {e}")
        return jsonify({'success': False, 'error': str(e)})

@app.route('/s/<token>')
def shared_item(token):
    """Просмотр общего файла или папки (короткая ссылка)"""
    shared_files = get_shared_files()
    if token in shared_files:
        data = shared_files[token]
        p = os.path.join(CONFIG['UPLOAD_FOLDER'], data['path'])
        if os.path.exists(p):
            return send_from_directory(os.path.dirname(p), os.path.basename(p), as_attachment=False)
        else:
            return "Файл не найден", 404
    
    shared_folders = get_shared_folders()
    if token in shared_folders:
        data = shared_folders[token]
        folder_path = os.path.join(CONFIG['UPLOAD_FOLDER'], data['path'])
        
        subpath = request.args.get('path', '')
        current_path = os.path.join(folder_path, subpath) if subpath else folder_path
        
        if os.path.exists(current_path) and os.path.isdir(current_path):
            filenames_db = get_filenames_db()
            foldernames_db = get_foldernames_db()
            
            breadcrumb_parts = [f'<a href="/s/{token}">{data["name"]}</a>']
            if subpath:
                subparts = subpath.split('/')
                current_sub = ''
                for i, part in enumerate(subparts):
                    current_sub += part + '/' if i < len(subparts) - 1 else part
                    display_part = foldernames_db.get(part, part)
                    breadcrumb_parts.append(f' / <a href="/s/{token}?path={current_sub}">{display_part}</a>')
            
            breadcrumb = ''.join(breadcrumb_parts)
            
            gallery_items = []
            items = []
            
            for item in os.listdir(current_path):
                item_path = os.path.join(current_path, item)
                if os.path.isdir(item_path):
                    display_name = foldernames_db.get(item, item)
                    items.append({
                        'name': item,
                        'display_name': display_name,
                        'path': os.path.join(subpath, item) if subpath else item,
                        'is_file': False,
                        'is_folder': True
                    })
                else:
                    file_ext = item.lower().split('.')[-1] if '.' in item else ''
                    is_image = file_ext in ['jpg', 'jpeg', 'png', 'gif', 'webp']
                    is_video = file_ext in ['mp4', 'webm', 'avi', 'mov']
                    is_pdf = file_ext == 'pdf'
                    display_name = filenames_db.get(item, item)
                    file_url = f'/s_file/{token}/{os.path.join(subpath, item) if subpath else item}'
                    
                    if is_image or is_video:
                        gallery_items.append({
                            'url': file_url,
                            'type': 'video' if is_video else 'image',
                            'name': display_name
                        })
                    
                    items.append({
                        'name': item,
                        'display_name': display_name,
                        'size': os.path.getsize(item_path),
                        'is_file': True,
                        'is_image': is_image,
                        'is_video': is_video,
                        'is_pdf': is_pdf,
                        'url': file_url
                    })
            
            items.sort(key=lambda x: (not x.get('is_folder', False), x['display_name'].lower()))
            
            html = f'''
            <!DOCTYPE html>
            <html lang="ru">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
                <title>Общая папка: {data['name']}</title>
                <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
                <style>
                    * {{ margin: 0; padding: 0; box-sizing: border-box; }}
                    body {{ font-family: sans-serif; background: #f5f5f5; }}
                    .container {{ max-width: 1200px; margin: 0 auto; background: white; min-height: 100vh; }}
                    .header {{ background: #222; color: white; padding: 15px 20px; }}
                    .breadcrumb {{ padding: 15px 20px; background: #f0f0f0; border-bottom: 1px solid #ddd; }}
                    .breadcrumb a {{ color: #007bff; text-decoration: none; }}
                    .breadcrumb a:hover {{ text-decoration: underline; }}
                    .content {{ padding: 20px; }}
                    .file-list {{ display: flex; flex-wrap: wrap; gap: 20px; }}
                    .file-item {{ 
                        width: 200px; 
                        padding: 15px; 
                        border: 1px solid #ddd; 
                        border-radius: 10px;
                        text-align: center;
                        cursor: pointer;
                        transition: transform 0.2s, box-shadow 0.2s;
                        background: white;
                    }}
                    .file-item:hover {{ transform: translateY(-5px); box-shadow: 0 5px 15px rgba(0,0,0,0.1); }}
                    .file-preview {{ 
                        width: 100%; 
                        height: 150px; 
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        overflow: hidden;
                        margin-bottom: 10px;
                        background: #f9f9f9;
                        border-radius: 5px;
                    }}
                    .file-preview img {{ max-width: 100%; max-height: 100%; object-fit: contain; }}
                    .file-preview video {{ max-width: 100%; max-height: 100%; }}
                    .file-preview iframe {{ width: 100%; height: 100%; border: none; }}
                    .file-icon {{ font-size: 48px; }}
                    .file-name {{ 
                        color: #007bff; 
                        text-decoration: none;
                        word-break: break-all;
                        display: block;
                        margin-top: 10px;
                        font-size: 12px;
                    }}
                    .file-name:hover {{ text-decoration: underline; }}
                    .folder-item {{ cursor: pointer; }}
                    .folder-icon {{ font-size: 48px; }}
                    .gallery-overlay {{ 
                        display: none; 
                        position: fixed; 
                        top: 0; 
                        left: 0; 
                        width: 100%; 
                        height: 100%; 
                        background: rgba(0,0,0,0.95); 
                        z-index: 2000; 
                        align-items: center; 
                        justify-content: center;
                    }}
                    .gallery-content {{
                        display: flex;
                        flex-direction: column;
                        align-items: center;
                        justify-content: center;
                        width: 100%;
                        height: 100%;
                        position: relative;
                    }}
                    .gallery-nav {{
                        position: absolute;
                        top: 50%;
                        transform: translateY(-50%);
                        font-size: 50px;
                        color: white;
                        cursor: pointer;
                        background: rgba(0,0,0,0.5);
                        width: 60px;
                        height: 80px;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        border-radius: 10px;
                        transition: background 0.3s;
                        z-index: 2002;
                    }}
                    .gallery-nav:hover {{ background: rgba(0,0,0,0.8); }}
                    .gallery-nav-prev {{ left: 20px; }}
                    .gallery-nav-next {{ right: 20px; }}
                    .gallery-media {{
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        max-width: 90vw;
                        max-height: 80vh;
                    }}
                    .gallery-media img {{
                        max-width: 100%;
                        max-height: 80vh;
                        object-fit: contain;
                        cursor: pointer;
                        transition: transform 0.2s ease;
                    }}
                    .gallery-media video {{
                        max-width: 95vw;
                        max-height: 80vh;
                        cursor: pointer;
                    }}
                    .gallery-filename {{
                        position: absolute;
                        bottom: 20px;
                        left: 50%;
                        transform: translateX(-50%);
                        background: rgba(0,0,0,0.7);
                        color: white;
                        padding: 8px 16px;
                        border-radius: 20px;
                        font-size: 14px;
                        z-index: 2002;
                        white-space: nowrap;
                        max-width: 80%;
                        overflow-x: auto;
                        text-overflow: ellipsis;
                    }}
                    .close-gallery {{ 
                        position: absolute; 
                        top: 20px; 
                        right: 20px; 
                        font-size: 40px; 
                        cursor: pointer; 
                        color: white; 
                        z-index: 2001;
                        background: rgba(0,0,0,0.5);
                        width: 50px;
                        height: 50px;
                        border-radius: 25px;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        transition: background 0.3s;
                    }}
                    .close-gallery:hover {{ background: rgba(0,0,0,0.8); }}
                    @media (max-width: 768px) {{
                        .gallery-nav {{ width: 40px; height: 60px; font-size: 30px; }}
                        .gallery-filename {{ font-size: 10px; padding: 4px 8px; bottom: 10px; }}
                    }}
                </style>
            </head>
            <body>
                <div class="container">
                    <div class="header">
                        <strong>Общая папка</strong>
                    </div>
                    <div class="breadcrumb">
                        {breadcrumb}
                    </div>
                    <div class="content">
                        <div class="file-list">
            '''
            
            for item in items:
                if item.get('is_folder'):
                    folder_url = f'/s/{token}?path={item["path"]}'
                    html += f'''
                        <div class="file-item folder-item" onclick="window.location.href='{folder_url}'">
                            <div class="file-preview">
                                <div class="file-icon">📁</div>
                            </div>
                            <div class="file-name">{item['display_name']}</div>
                        </div>
                    '''
                else:
                    preview_html = ''
                    if item['is_image']:
                        preview_html = f'<img class="gallery-trigger" src="{item["url"]}" style="max-width:100%; max-height:100%; object-fit:contain;">'
                    elif item['is_video']:
                        preview_html = f'<video class="gallery-trigger" src="{item["url"]}" style="max-width:100%; max-height:100%;" preload="metadata"></video>'
                    elif item['is_pdf']:
                        preview_html = f'<div class="pdf-preview" style="cursor:pointer; text-align:center; padding:20px; background:#f5f5f5; border-radius:5px;" onclick="window.open(\'{item["url"]}?view=1\', \'_blank\')">📄 PDF документ<br><span style="font-size:12px; color:#666;">Кликните для просмотра</span></div>'
                    else:
                        preview_html = '<div class="file-icon">📄</div>'
                    
                    html += f'''
                        <div class="file-item" data-url="{item['url']}" data-type="{'video' if item['is_video'] else 'image' if item['is_image'] else 'pdf' if item['is_pdf'] else 'file'}" data-name="{item['display_name']}">
                            <div class="file-preview">
                                {preview_html}
                            </div>
                            <a href="{item['url']}?dl=1" download class="file-name">{item['display_name']}</a>
                        </div>
                    '''
            
            html += f'''
                        </div>
                    </div>
                </div>
                <div id="gallery-overlay" class="gallery-overlay">
                    <div id="gallery-content" class="gallery-content"></div>
                    <div class="gallery-nav gallery-nav-prev" id="gallery-prev">❮</div>
                    <div class="gallery-nav gallery-nav-next" id="gallery-next">❯</div>
                    <div id="close-gallery" class="close-gallery">&times;</div>
                </div>
                <script>
                    let galleryItems = {json.dumps(gallery_items)};
                    let currentGalleryIndex = 0;
                    
                    function showGalleryItem() {{
                        const item = galleryItems[currentGalleryIndex];
                        if (!item) return;
                        
                        let mediaHtml;
                        if (item.type === 'video') {{
                            mediaHtml = '<video src="' + item.url + '" controls autoplay class="gallery-media-video"></video>';
                        }} else {{
                            mediaHtml = '<img src="' + item.url + '" class="gallery-media-img">';
                        }}
                        
                        const html = `
                            <div class="gallery-media">
                                ${{mediaHtml}}
                            </div>
                            <div class="gallery-filename">${{item.name}}</div>
                        `;
                        $('#gallery-content').html(html);
                        
                        if (item.type !== 'video') {{
                            const img = $('#gallery-content .gallery-media-img');
                            let zoomed = false;
                            img.off('click').on('click', function(e) {{
                                e.stopPropagation();
                                if (!zoomed) {{
                                    $(this).css({{
                                        'transform': 'scale(2)',
                                        'cursor': 'zoom-out'
                                    }});
                                    zoomed = true;
                                }} else {{
                                    $(this).css({{
                                        'transform': 'scale(1)',
                                        'cursor': 'zoom-in'
                                    }});
                                    zoomed = false;
                                }}
                            }});
                        }}
                        
                        $('#gallery-prev').css('opacity', currentGalleryIndex === 0 ? '0.3' : '1');
                        $('#gallery-next').css('opacity', currentGalleryIndex === galleryItems.length - 1 ? '0.3' : '1');
                    }}
                    
                    function nextGalleryItem() {{
                        if (currentGalleryIndex < galleryItems.length - 1) {{
                            currentGalleryIndex++;
                            showGalleryItem();
                        }}
                    }}
                    
                    function prevGalleryItem() {{
                        if (currentGalleryIndex > 0) {{
                            currentGalleryIndex--;
                            showGalleryItem();
                        }}
                    }}
                    
                    $('.gallery-trigger').on('click', function(e) {{
                        e.stopPropagation();
                        const url = $(this).attr('src');
                        const name = $(this).closest('.file-item').data('name');
                        const index = galleryItems.findIndex(item => item.url === url);
                        if (index !== -1) {{
                            currentGalleryIndex = index;
                            showGalleryItem();
                            $('#gallery-overlay').css('display', 'flex');
                        }}
                    }});
                    
                    $('#gallery-next').on('click', function(e) {{
                        e.stopPropagation();
                        nextGalleryItem();
                    }});
                    
                    $('#gallery-prev').on('click', function(e) {{
                        e.stopPropagation();
                        prevGalleryItem();
                    }});
                    
                    $('#close-gallery').on('click', function(e) {{
                        e.stopPropagation();
                        $('#gallery-overlay').hide();
                        $('#gallery-content').empty();
                    }});
                    
                    $('#gallery-overlay').on('click', function(e) {{
                        if (e.target === this) {{
                            $('#gallery-overlay').hide();
                            $('#gallery-content').empty();
                        }}
                    }});
                    
                    $(document).on('keydown', function(e) {{
                        if ($('#gallery-overlay').is(':visible')) {{
                            if (e.key === 'ArrowLeft') {{
                                prevGalleryItem();
                            }} else if (e.key === 'ArrowRight') {{
                                nextGalleryItem();
                            }} else if (e.key === 'Escape') {{
                                $('#gallery-overlay').hide();
                                $('#gallery-content').empty();
                            }}
                        }}
                    }});
                </script>
            </body>
            </html>
            '''
            return html
        else:
            return "Папка не найдена", 404
    
    return "Ссылка недействительна", 404

@app.route('/s_file/<token>/<path:filename>')
def shared_file(token, filename):
    """Получение файла из общей папки"""
    shared_folders = get_shared_folders()
    if token in shared_folders:
        data = shared_folders[token]
        folder_path = os.path.join(CONFIG['UPLOAD_FOLDER'], data['path'])
        file_path = os.path.join(folder_path, filename)
        if os.path.exists(file_path) and os.path.isfile(file_path):
            if request.args.get('dl') == '1':
                return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path), as_attachment=True)
            return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path), as_attachment=False)
    return "Файл не найден", 404

@app.route('/space_info')
def space_info():
    if not session.get('logged_in'):
        return jsonify({'error': 'Не авторизован'}), 401
    used = get_user_used_space(session['user_login'])
    quota = get_user_quota(session['user_login'])
    return jsonify({
        'total_space': format_size(quota) if quota is not None else "∞",
        'free_space': format_size(quota - used) if quota is not None else "∞"
    })

@app.route('/create_folder', methods=['POST'])
def create_folder():
    try:
        if not session.get('logged_in'):
            return jsonify({'success': False, 'error': 'Не авторизован'}), 401
        
        folder_name = request.form.get('folder_name', '').strip()
        current_path = request.form.get('current_path', '')
        
        if not folder_name:
            return jsonify({'success': False, 'error': 'Имя папки не может быть пустым'})
        
        latin_name = secure_folder_name(folder_name)
        if not latin_name:
            return jsonify({'success': False, 'error': 'Недопустимое имя папки'})
        
        u = session['user_login']
        base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
        parent_dir = os.path.join(base_path, current_path) if current_path else base_path
        new_folder_path = os.path.join(parent_dir, latin_name)
        
        if os.path.exists(new_folder_path):
            return jsonify({'success': False, 'error': 'Папка с таким именем уже существует'})
        
        os.makedirs(new_folder_path, exist_ok=False)
        add_folder_mapping(latin_name, folder_name)
        
        return jsonify({'success': True})
    except FileExistsError:
        return jsonify({'success': False, 'error': 'Папка с таким именем уже существует'})
    except Exception as e:
        print(f"Ошибка создания папки: {e}")
        traceback.print_exc()
        return jsonify({'success': False, 'error': f'Ошибка: {str(e)}'})

@app.route('/rename_folder', methods=['POST'])
def rename_folder():
    try:
        if not session.get('logged_in'):
            return jsonify({'success': False, 'error': 'Не авторизован'}), 401
        
        old_path = request.form.get('old_path', '')
        new_name = request.form.get('new_name', '').strip()
        
        if not new_name:
            return jsonify({'success': False, 'error': 'Имя папки не может быть пустым'})
        
        latin_new_name = secure_folder_name(new_name)
        if not latin_new_name:
            return jsonify({'success': False, 'error': 'Недопустимое имя папки'})
        
        u = session['user_login']
        base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
        old_folder_path = os.path.join(base_path, old_path)
        parent_dir = os.path.dirname(old_folder_path)
        new_folder_path = os.path.join(parent_dir, latin_new_name)
        
        old_latin_name = os.path.basename(old_folder_path)
        
        os.rename(old_folder_path, new_folder_path)
        update_folder_mapping(old_latin_name, latin_new_name, new_name)
        
        shared_folders = get_shared_folders()
        full_old_path = os.path.join(u, old_path)
        for token, data in shared_folders.items():
            if data.get('path') == full_old_path:
                new_full_path = os.path.join(u, os.path.dirname(old_path), latin_new_name)
                data['path'] = new_full_path
                data['name'] = new_name
                save_shared_folders(shared_folders)
                break
        
        return jsonify({'success': True})
    except FileExistsError:
        return jsonify({'success': False, 'error': 'Папка с таким именем уже существует'})
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)})

@app.route('/rename_file', methods=['POST'])
def rename_file():
    if not session.get('logged_in'):
        return jsonify({'success': False, 'error': 'Не авторизован'}), 401
    
    old_path = request.form.get('old_path', '')
    new_name = request.form.get('new_name', '').strip()
    
    if not new_name:
        return jsonify({'success': False, 'error': 'Имя файла не может быть пустым'})
    
    old_ext = os.path.splitext(old_path)[1]
    new_name_clean = secure_filename(new_name)
    if not new_name_clean:
        return jsonify({'success': False, 'error': 'Недопустимое имя файла'})
    
    new_filename = new_name_clean + old_ext
    
    u = session['user_login']
    base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
    old_file_path = os.path.join(base_path, old_path)
    parent_dir = os.path.dirname(old_file_path)
    new_file_path = os.path.join(parent_dir, new_filename)
    
    original_name = get_original_filename(os.path.basename(old_path))
    original_name_without_ext = os.path.splitext(original_name)[0]
    
    try:
        os.rename(old_file_path, new_file_path)
        update_filename_mapping(os.path.basename(old_path), new_filename, original_name_without_ext + old_ext)
        
        shared_files = get_shared_files()
        full_old_path = os.path.join(u, old_path)
        for token, data in shared_files.items():
            if data.get('path') == full_old_path:
                new_full_path = os.path.join(u, os.path.dirname(old_path), new_filename)
                data['path'] = new_full_path
                data['name'] = original_name_without_ext + old_ext
                save_shared_files(shared_files)
                break
        
        return jsonify({'success': True})
    except FileExistsError:
        return jsonify({'success': False, 'error': 'Файл с таким именем уже существует'})
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)})

@app.route('/move_file', methods=['POST'])
def move_file():
    if not session.get('logged_in'):
        return jsonify({'success': False, 'error': 'Не авторизован'}), 401
    
    file_path = request.form.get('file_path', '')
    target_folder = request.form.get('target_folder', '')
    
    u = session['user_login']
    base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
    source_path = os.path.join(base_path, file_path)
    target_dir = os.path.join(base_path, target_folder) if target_folder else base_path
    target_path = os.path.join(target_dir, os.path.basename(file_path))
    
    try:
        shutil.move(source_path, target_path)
        
        shared_files = get_shared_files()
        full_old_path = os.path.join(u, file_path)
        for token, data in shared_files.items():
            if data.get('path') == full_old_path:
                new_full_path = os.path.join(u, target_folder, os.path.basename(file_path)) if target_folder else os.path.join(u, os.path.basename(file_path))
                data['path'] = new_full_path
                save_shared_files(shared_files)
                break
        
        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)})

@app.route('/get_folders')
def get_folders():
    if not session.get('logged_in'):
        return jsonify({'folders': []}), 401
    
    u = session['user_login']
    base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
    foldernames_db = get_foldernames_db()
    
    folders = []
    for root, dirs, _ in os.walk(base_path):
        for dir_name in dirs:
            if not is_system_folder(dir_name):
                rel_path = os.path.relpath(os.path.join(root, dir_name), base_path)
                if rel_path != '.':
                    display_name = foldernames_db.get(dir_name, dir_name)
                    folders.append({
                        'name': dir_name,
                        'display_name': display_name,
                        'path': rel_path
                    })
    
    return jsonify({'folders': folders})

@app.route('/delete', methods=['POST'])
def delete():
    if not session.get('logged_in'): return abort(401)
    p = request.form.get('path')
    item_type = request.form.get('type', 'file')
    u = session['user_login']
    full = os.path.join(CONFIG['UPLOAD_FOLDER'], u, p)
    
    if os.path.exists(full):
        if os.path.isdir(full):
            shutil.rmtree(full)
            latin_name = os.path.basename(full)
            delete_folder_mapping(latin_name)
            shared_folders = get_shared_folders()
            for token, data in list(shared_folders.items()):
                if data.get('path') == os.path.join(u, p):
                    unshare_folder(token)
        else:
            os.remove(full)
            delete_filename_mapping(os.path.basename(p))
            shared_files = get_shared_files()
            for token, data in list(shared_files.items()):
                if data.get('path') == os.path.join(u, p):
                    unshare_file(token)
    
    return jsonify(True)

@app.route('/login', methods=['POST'])
def login():
    l = request.form.get('login')
    p = request.form.get('password')
    u = verify_user(l, p)
    if u:
        session['logged_in'] = True
        session['user_login'] = u['login']
        session['user_name'] = u['name']
    return redirect('/')

@app.route('/logout')
def logout():
    session.clear()
    return redirect('/')

@app.route('/change_password', methods=['POST'])
def change_password():
    if not session.get('logged_in'):
        return jsonify({'success': False, 'error': 'Не авторизован'}), 401
    new_password = request.form.get('new_password')
    confirm_password = request.form.get('confirm_password')
    if not new_password or not confirm_password:
        return jsonify({'success': False, 'error': 'Все поля обязательны'})
    if new_password != confirm_password:
        return jsonify({'success': False, 'error': 'Пароли не совпадают'})
    if len(new_password) < 3:
        return jsonify({'success': False, 'error': 'Пароль должен содержать минимум 3 символа'})
    if update_user_password(session['user_login'], new_password):
        return jsonify({'success': True})
    return jsonify({'success': False, 'error': 'Пользователь не найден'})

@app.route('/upload', methods=['POST'])
def upload():
    if not session.get('logged_in'):
        return jsonify({'error': 'Не авторизован'}), 401
    
    u = session['user_login']
    current_path = request.form.get('current_path', '')
    
    total_size = 0
    files = request.files.getlist('files')
    for f in files:
        if f.filename:
            f.seek(0, 2)
            size = f.tell()
            f.seek(0)
            total_size += size
    
    has_space, remaining = check_user_quota(u, total_size)
    if not has_space:
        return jsonify({'error': f'Недостаточно места. Свободно: {format_size(remaining)}'}), 400
    
    base_path = os.path.join(CONFIG['UPLOAD_FOLDER'], u)
    
    if not current_path:
        date_folder = datetime.now().strftime("INPUT_%Y%m%d")
        target_dir = os.path.join(base_path, date_folder)
    else:
        target_dir = os.path.join(base_path, current_path)
    
    os.makedirs(target_dir, exist_ok=True)
    
    for f in files:
        if f.filename:
            original_filename = f.filename
            latin_filename = secure_filename_with_translit(original_filename)
            add_filename_mapping(latin_filename, original_filename)
            filepath = os.path.join(target_dir, latin_filename)
            counter = 1
            while os.path.exists(filepath):
                name, ext = os.path.splitext(latin_filename)
                filepath = os.path.join(target_dir, f"{name}_{counter}{ext}")
                counter += 1
            f.save(filepath)
    
    return jsonify({'success': True})

@app.route('/download/<path:f>')
def download(f):
    if not session.get('logged_in'): return abort(401)
    latin_name = os.path.basename(f)
    original_name = get_original_filename(latin_name)
    full_path = os.path.join(CONFIG['UPLOAD_FOLDER'], f)
    
    # Для просмотра PDF в браузере
    if request.args.get('view') == '1':
        return send_from_directory(os.path.dirname(full_path), os.path.basename(full_path), as_attachment=False)
    else:
        return send_from_directory(os.path.dirname(full_path), os.path.basename(full_path), as_attachment=True, download_name=original_name)

@app.route('/favicon.ico')
def favicon():
    return '', 204

application = app

if __name__ == '__main__':
    print("Запуск в режиме отладки")
    app.run(host='127.0.0.1', port=5000, debug=True)
