/**
 * Copyright (c) 2024-2026 Тарабанов Александр Викторович
 * All rights reserved.
 * 
 * This software is proprietary and confidential.
 * Unauthorized copying, modification, or distribution is prohibited.
 * 
 * For licensing inquiries: info@hb3-accelerator.com
 * Website: https://hb3-accelerator.com
 * GitHub: https://github.com/VC-HB3-Accelerator
 */

const express = require('express');
const router = express.Router();
const crypto = require('crypto');
const db = require('../db');
const encryptedDb = require('../services/encryptedDatabaseService');
const logger = require('../utils/logger');
const rateLimit = require('express-rate-limit');
const { requireAuth } = require('../middleware/auth');
const authService = require('../services/auth-service');
const { ethers } = require('ethers');
const botManager = require('../services/botManager');
const emailAuth = require('../services/emailAuth');
const verificationService = require('../services/verification-service');
const identityService = require('../services/identity-service');
const sessionService = require('../services/session-service');
// Используем централизованный сервис для работы с согласиями
const consentService = require('../services/consentService');
const { DOCUMENT_CONSENT_MAP } = consentService;

// Создаем лимитер для попыток аутентификации (отключено - лимиты убраны)
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 минут
  max: 1000000, // Очень большой лимит (практически без ограничений)
  standardHeaders: true,
  legacyHeaders: false,
  message: { error: 'Слишком много попыток аутентификации. Попробуйте позже.' },
});

// Получение nonce для аутентификации
router.get('/nonce', async (req, res) => {
  try {
    const { address } = req.query;
    if (!address) {
      return res.status(400).json({ error: 'Address is required' });
    }

    // Нормализуем адрес: сначала через ethers.getAddress (EIP-55 checksum), потом toLowerCase для хранения
    // Это гарантирует, что адрес валиден и всегда сохраняется в нижнем регистре
    let normalizedAddress;
    try {
      normalizedAddress = ethers.getAddress(address).toLowerCase();
    } catch (error) {
      logger.error(`[nonce] Invalid address format: ${address}`, error);
      return res.status(400).json({ error: 'Invalid address format' });
    }

    // Очищаем истекшие nonce перед генерацией нового
    try {
      await db.getQuery()(
        'DELETE FROM nonces WHERE expires_at < NOW()'
      );
      logger.info(`[nonce] Cleaned up expired nonces`);
    } catch (cleanupError) {
      logger.warn(`[nonce] Error cleaning up expired nonces: ${cleanupError.message}`);
    }

    // Генерируем случайный nonce
    const nonce = crypto.randomBytes(16).toString('hex');
    logger.info(`[nonce] Generated nonce: ${nonce}`);

    // Используем правильный ключ шифрования
    const fs = require('fs');
    const path = require('path');
    // Получаем ключ шифрования через унифицированную утилиту
    const encryptionUtils = require('../utils/encryptionUtils');
    const encryptionKey = encryptionUtils.getEncryptionKey();
    logger.info(`[nonce] Using encryption key: ${encryptionKey.substring(0, 10)}...`);
    
    try {
      // Проверяем, существует ли уже nonce для этого адреса
      // Используем normalizedAddress (уже в нижнем регистре)
      const existingNonces = await db.getQuery()(
        'SELECT id FROM nonces WHERE identity_value_encrypted = encrypt_text($1, $2)',
        [normalizedAddress, encryptionKey]
      );

      if (existingNonces.rows.length > 0) {
        // Обновляем существующий nonce
        logger.info(`[nonce] Updating existing nonce for address: ${normalizedAddress}`);
        await db.getQuery()(
          'UPDATE nonces SET nonce_encrypted = encrypt_text($1, $2), expires_at = $3 WHERE id = $4',
          [nonce, encryptionKey, new Date(Date.now() + 15 * 60 * 1000), existingNonces.rows[0].id]
        );
      } else {
        // Создаем новый nonce
        logger.info(`[nonce] Creating new nonce for address: ${normalizedAddress}`);
        await db.getQuery()(
          'INSERT INTO nonces (identity_value_encrypted, nonce_encrypted, expires_at) VALUES (encrypt_text($1, $2), encrypt_text($3, $2), $4)',
          [normalizedAddress, encryptionKey, nonce, new Date(Date.now() + 15 * 60 * 1000)]
        );
      }
    } catch (dbError) {
      console.error('Database error:', dbError);
      // Fallback: просто возвращаем nonce без сохранения в БД
      logger.warn(`Nonce ${nonce} generated for address ${normalizedAddress} but not saved to DB due to error`);
    }

    logger.info(`Nonce ${nonce} сохранен для адреса ${normalizedAddress}`);

    res.json({ nonce });
  } catch (error) {
    logger.error('Error generating nonce:', error);
    res.status(500).json({ error: 'Failed to generate nonce' });
  }
});

// Верификация подписи и создание сессии
router.post('/verify', async (req, res) => {
  try {
    const { address, signature, nonce, issuedAt } = req.body;

    logger.info(`[verify] Verifying signature for address: ${address}`);
    logger.info(`[verify] Request body:`, JSON.stringify(req.body, null, 2));
    logger.info(`[verify] Request headers:`, JSON.stringify(req.headers, null, 2));
    logger.info(`[verify] Raw request body:`, req.body);
    logger.info(`[verify] Request body type:`, typeof req.body);
    logger.info(`[verify] Request body keys:`, Object.keys(req.body || {}));
    logger.info(`[verify] Nonce from request: ${nonce}`);
    logger.info(`[verify] Address from request: ${address}`);
    logger.info(`[verify] Signature from request: ${signature}`);

    // Сохраняем гостевые ID до проверки
    const guestId = req.session.guestId;
    const previousGuestId = req.session.previousGuestId;

    // Нормализуем адрес для использования в запросах
    const normalizedAddress = ethers.getAddress(address);
    const normalizedAddressLower = normalizedAddress.toLowerCase();

    // Читаем ключ шифрования
    const fs = require('fs');
    const path = require('path');
    // Получаем ключ шифрования через унифицированную утилиту
    const encryptionUtils = require('../utils/encryptionUtils');
    const encryptionKey = encryptionUtils.getEncryptionKey();

    // Проверяем nonce в базе данных с проверкой времени истечения
    // ВАЖНО: nonce привязан к адресу, поэтому проверяем для того адреса, который пришел в запросе
    logger.info(`[verify] Checking nonce for address: ${normalizedAddressLower} (normalized from: ${address})`);
    const nonceResult = await db.getQuery()(
      'SELECT nonce_encrypted, expires_at FROM nonces WHERE identity_value_encrypted = encrypt_text($1, $2)',
      [normalizedAddressLower, encryptionKey]
    );
    
    if (nonceResult.rows.length === 0) {
      logger.error(`[verify] Nonce not found for address: ${normalizedAddressLower}`);
      logger.error(`[verify] This may happen if user switched wallet between nonce request and signature`);
      return res.status(401).json({ success: false, error: 'Nonce not found. Please request a new nonce.' });
    }

    // Проверяем, не истек ли срок действия nonce
    const expiresAt = new Date(nonceResult.rows[0].expires_at);
    const now = new Date();
    if (now > expiresAt) {
      logger.error(`[verify] Nonce expired for address: ${normalizedAddressLower}. Expired at: ${expiresAt}, Now: ${now}`);
      return res.status(401).json({ success: false, error: 'Nonce expired' });
    }

    // Расшифровываем nonce из базы данных
    const storedNonce = await db.getQuery()(
      'SELECT decrypt_text(nonce_encrypted, $1) as nonce FROM nonces WHERE identity_value_encrypted = encrypt_text($2, $1)',
      [encryptionKey, normalizedAddressLower]
    );

    logger.info(`[verify] Stored nonce from DB: ${storedNonce.rows[0]?.nonce}`);
    logger.info(`[verify] Nonce from request: ${nonce}`);
    logger.info(`[verify] Nonce match: ${storedNonce.rows[0]?.nonce === nonce}`);
    logger.info(`[verify] Stored nonce length: ${storedNonce.rows[0]?.nonce?.length}`);
    logger.info(`[verify] Request nonce length: ${nonce?.length}`);

    if (storedNonce.rows.length === 0 || storedNonce.rows[0].nonce !== nonce) {
      logger.error(`[verify] Invalid nonce for address: ${normalizedAddressLower}. Expected: ${storedNonce.rows[0]?.nonce}, Got: ${nonce}`);
      logger.error(`[verify] Stored nonce type: ${typeof storedNonce.rows[0]?.nonce}, Request nonce type: ${typeof nonce}`);
      return res.status(401).json({ success: false, error: 'Invalid nonce' });
    }

    // ВАЖНО: Для SIWE сообщения ВСЕГДА используем хост из запроса, чтобы он совпадал с фронтендом
    // Фронтенд использует window.location.host, поэтому бэкенд должен использовать req.get('host')
    // Логика формирования domain должна точно соответствовать фронтенду
    const protocol = req.protocol || 'http';
    let host = req.get('host') || 'localhost:9000';

    logger.info(`[verify] Request protocol: ${protocol}, host header: ${req.get('host')}`);

    // Формируем domain для SIWE (должен совпадать с фронтендом)
    // Используем ту же логику, что и на фронтенде: window.location.host + добавление порта для localhost/IP
    let domain = host;
    if (!domain.includes(':')) {
      // Извлекаем hostname из host (если порта нет, host = hostname)
      const hostname = host;
      if (hostname === 'localhost' || hostname === '127.0.0.1') {
        domain = `${hostname}:9000`;
      } else if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
        // IP адрес - добавляем порт
        domain = `${hostname}:9000`;
      }
    }

    // Формируем origin и baseUrl для resources
    // ВАЖНО: origin должен совпадать с origin на фронтенде (getOrigin()),
    // поэтому используем именно domain (с портом), а не host из заголовка
    const origin = `${protocol}://${domain}`;
    const baseUrlForResources = origin;
    
    // Получаем список документов для подписания и добавляем их в resources
    const documentTitles = Object.keys(DOCUMENT_CONSENT_MAP);
    const tableName = 'admin_pages_simple';
    const tableExistsRes = await db.getQuery()(
      `SELECT to_regclass($1) as exists`, [tableName]
    );
    
    let resources = [`${baseUrlForResources}/api/auth/verify`];
    // Добавляем общую ссылку на страницу опубликованных документов
    resources.push(`${baseUrlForResources}/content/published`);
    if (tableExistsRes.rows[0].exists) {
      const { rows: documents } = await db.getQuery()(`
        SELECT id FROM ${tableName} 
        WHERE status = 'published' 
          AND visibility = 'public'
          AND title = ANY($1)
      `, [documentTitles]);
      
      // Добавляем ссылки на документы в resources (используем домен из БД)
      documents.forEach(doc => {
        resources.push(`${baseUrlForResources}/content/published/${doc.id}`);
      });
    }
    
    // Сортируем resources для консистентности
    resources = resources.sort();
    
    // Используем issuedAt из запроса, если он есть, иначе создаем новый
    const messageIssuedAt = issuedAt || new Date().toISOString();
    
    const { SiweMessage } = require('siwe');
    
    // Реконструируем SIWE-сообщение на бэкенде, НО уже с теми же полями,
    // что и на фронтенде: domain, origin (uri), resources
    const message = new SiweMessage({
      domain,
      address: normalizedAddress,
      statement: 'Sign in with Ethereum to the app.\n\nПодписывая это сообщение, вы подтверждаете ознакомление с документами, указанными в Resources, и согласие на обработку персональных данных.',
      uri: origin,
      version: '1',
      chainId: 1,
      nonce: nonce,
      issuedAt: messageIssuedAt,
      resources: resources,
    });
    const messageToVerify = message;
    
    const messageToSign = message.prepareMessage();
    
    logger.info(`[verify] SIWE message for verification: ${messageToSign}`);
    logger.info(`[verify] Resources (backend expectation): ${JSON.stringify(resources)}`);
    logger.info(`[verify] IssuedAt (backend): ${messageIssuedAt}`);
    logger.info(`[verify] Domain (backend): ${domain}, Origin (backend): ${origin}`);
    logger.info(`[verify] Normalized address from request: ${normalizedAddress}`);
    logger.info(`[verify] Request headers origin: ${req.get('origin')}`);
    logger.info(`[verify] Request headers host: ${req.get('host')}`);
    logger.info(`[verify] Request headers referer: ${req.get('referer')}`);

    // Проверяем подпись через SiweMessage.verify()
    const isValid = await authService.verifySignature(messageToVerify, signature, normalizedAddress);
    if (!isValid) {
      logger.error(`[verify] Invalid signature for address: ${normalizedAddress}`);
      return res.status(401).json({ success: false, error: 'Invalid signature' });
    }

    // СРАЗУ проверяем уровень доступа пользователя
    logger.info(`[verify] Checking access level for address: ${normalizedAddress}`);
    let userAccessLevel = await authService.getUserAccessLevel(normalizedAddress);
    logger.info(`[verify] Access level determined: ${userAccessLevel.level} (${userAccessLevel.tokenCount} tokens)`);

    let userId;

    // Проверяем, авторизован ли пользователь уже
    if (req.session.authenticated && req.session.userId) {
      // Если пользователь уже авторизован, привязываем кошелек к существующему пользователю
      userId = req.session.userId;
      logger.info(
        `[verify] Using existing authenticated user ${userId} for wallet ${normalizedAddress}`
      );

      // Связываем кошелек с пользователем через identity-service для предотвращения дубликатов
      await authService.linkIdentity(userId, 'wallet', address);

      // Если linkResult.message содержит 'already exists', значит кошелек уже привязан
      logger.info(
        `[verify] Wallet ${normalizedAddress} linked to user ${userId}: already exists`
      );
    } else {
      // Находим или создаем пользователя с уже известной ролью
      const result = await authService.findOrCreateUser(address, userAccessLevel);
      userId = result.userId;
      userAccessLevel = result.userAccessLevel;
      logger.info(`[verify] Found or created user ${userId} for wallet ${normalizedAddress} with access level: ${userAccessLevel.hasAccess}`);
    }

    // Сохраняем идентификаторы гостевой сессии
    if (guestId) {
      await identityService.saveIdentity(userId, 'guest', guestId, true);
    }

    if (previousGuestId && previousGuestId !== guestId) {
      await identityService.saveIdentity(userId, 'guest', previousGuestId, true);
    }

    // Обновляем сессию
    req.session.userId = userId;
    req.session.authenticated = true;
    req.session.authType = 'wallet';
    req.session.userAccessLevel = userAccessLevel;
    req.session.address = normalizedAddress; // Всегда сохраняем нормализованный адрес

    // Удаляем временный ID
    delete req.session.tempUserId;

    // Сохраняем сессию
    await sessionService.saveSession(req.session);

    // Связываем гостевые сообщения с пользователем
    await sessionService.linkGuestMessages(req.session, userId);

    // Проверяем согласия пользователя через централизованный сервис
    const consentCheck = await consentService.checkConsents({
      userId,
      walletAddress: normalizedAddress
    });
    
    const needsConsent = consentCheck.needsConsent;
    const missingConsents = consentCheck.missingConsents;

    // Возвращаем успешный ответ
    userAccessLevel = await authService.getUserAccessLevel(normalizedAddress);
    return res.json({
      success: true,
      userId,
      address: normalizedAddress, // Возвращаем нормализованный адрес
      userAccessLevel: userAccessLevel,
      authenticated: true,
      needsConsent: needsConsent,
      missingConsents: missingConsents,
    });
  } catch (error) {
    logger.error('[verify] Error:', error);
    res.status(500).json({ success: false, error: 'Server error' });
  }
});

// Аутентификация через Telegram
router.post('/telegram/verify', async (req, res) => {
  try {
    const { telegramId, verificationCode } = req.body;

    if (!telegramId || !verificationCode) {
      return res.status(400).json({
        success: false,
        error: 'Missing required fields',
      });
    }

    // Сохраняем гостевой ID из текущей сессии
    const guestId = req.session.guestId;

    // Передаем сессию в метод верификации
    const verificationResult = await authService.verifyTelegramAuth(
      telegramId,
      verificationCode,
      req.session
    );

    if (!verificationResult.success) {
      return res.status(400).json({
        success: false,
        error: verificationResult.error || 'Verification failed',
      });
    }

    // ---> ШАГ 4 И 5: ПОИСК ПРИВЯЗАННОГО КОШЕЛЬКА И ПРОВЕРКА БАЛАНСА <---
    let linkedWalletAddress = null;
    let finalIsAdmin = false; // Роль по умолчанию

    try {
        const walletIdentity = await identityService.findIdentity(verificationResult.userId, 'wallet');
        if (walletIdentity) {
            linkedWalletAddress = walletIdentity.provider_id;
            logger.info(`[telegram/verify] Found linked wallet ${linkedWalletAddress} for user ${verificationResult.userId}`);

            // Проверяем баланс токенов для определения роли
            const userAccessLevel = await authService.getUserAccessLevel(linkedWalletAddress);
            // Используем роль из userAccessLevel, которая уже правильно определена с учетом порогов
            const newRole = userAccessLevel.level;
            
            logger.info(`[telegram/verify] Role determined for ${linkedWalletAddress}: ${newRole} (tokens: ${userAccessLevel.tokenCount})`);

            // Обновляем роль в БД, если она отличается от текущей
            if (verificationResult.role !== newRole) {
                await db.getQuery()('UPDATE users SET role = $1 WHERE id = $2', [newRole, verificationResult.userId]);
                logger.info(`[telegram/verify] User role updated in DB for user ${verificationResult.userId} to ${newRole}`);
            }
            finalIsAdmin = (newRole === ROLES.EDITOR || newRole === ROLES.READONLY);
        } else {
            logger.info(`[telegram/verify] No linked wallet found for user ${verificationResult.userId}. Role remains '${verificationResult.role}'`);
            // Если кошелек не найден, используем роль из verificationResult (скорее всего 'user')
            finalIsAdmin = (verificationResult.role === ROLES.EDITOR || verificationResult.role === ROLES.READONLY);
        }
    } catch (error) {
        logger.error(`[telegram/verify] Error finding linked wallet or checking tokens for user ${verificationResult.userId}:`, error);
        // В случае ошибки, используем роль из verificationResult
        finalIsAdmin = (verificationResult.role === 'editor' || verificationResult.role === 'readonly');
    }
    // ---> КОНЕЦ ШАГОВ 4 И 5 <---

    // Создаем новую сессию для этого telegramId
    req.session.regenerate(async (err) => {
      if (err) {
        logger.error('[telegram/verify] Error regenerating session:', err);
        return res.status(500).json({
          success: false,
          error: 'Session error',
        });
      }

      // Устанавливаем данные в новой сессии
      req.session.userId = verificationResult.userId;
      req.session.telegramId = telegramId;
      req.session.authType = 'telegram';
      req.session.authenticated = true;
      req.session.userAccessLevel = finalIsAdmin ? { level: ROLES.EDITOR, tokenCount: 0, hasAccess: true } : { level: ROLES.USER, tokenCount: 0, hasAccess: false }; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА

      // ---> ДОБАВЛЯЕМ АДРЕС КОШЕЛЬКА В СЕССИЮ (ЕСЛИ НАЙДЕН) <---
      if (linkedWalletAddress) {
        req.session.address = linkedWalletAddress;
      }
      // ---> КОНЕЦ ДОБАВЛЕНИЯ АДРЕСА <---

      // Восстанавливаем гостевой ID, если он был
      if (guestId) {
        req.session.guestId = guestId;
      }

      // Сохраняем сессию
      await sessionService.saveSession(req.session);

      // Связываем гостевые сообщения только один раз
      if (guestId) {
        await sessionService.linkGuestMessages(req.session, verificationResult.userId);
      }

      // Получаем уровень доступа для пользователя
      let userAccessLevel = { level: ROLES.USER, tokenCount: 0, hasAccess: false };
      if (linkedWalletAddress) {
        userAccessLevel = await authService.getUserAccessLevel(linkedWalletAddress);
      }

      return res.json({
        success: true,
        userId: verificationResult.userId,
        userAccessLevel: userAccessLevel, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНЫЙ УРОВЕНЬ ДОСТУПА
        telegramId,
        isNewUser: verificationResult.isNewUser,
        address: linkedWalletAddress || null // <-- ВОЗВРАЩАЕМ АДРЕС КОШЕЛЬКА
      });
    });
  } catch (error) {
    logger.error('[telegram/verify] Error:', error);
    return res.status(500).json({
      success: false,
      error: 'Internal server error',
    });
  }
});

// Маршрут для запроса кода подтверждения по email
router.post('/email/request', authLimiter, async (req, res) => {
  try {
    const { email } = req.body;

    if (!email || !email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
      return res.status(400).json({ error: 'Invalid email format' });
    }

    // Инициализация email аутентификации
    const result = await emailAuth.initEmailAuth(req.session, email);

    // Сохраняем сессию после установки pendingEmail
    await sessionService.saveSession(req.session);

    if (result.success) {
      res.json({
        success: true,
        message: 'Код подтверждения отправлен на email',
      });
    } else {
      res.status(500).json({
        success: false,
        error: result.error || 'Ошибка отправки кода',
      });
    }
  } catch (error) {
    logger.error('Error requesting email code:', error);
    res.status(500).json({ error: error.message || 'Ошибка сервера' });
  }
});

// Маршрут для верификации email
router.post('/email/verify-code', async (req, res) => {
  try {
    const { code, email } = req.body;

    if (!code) {
      return res.status(400).json({
        success: false,
        error: 'Код подтверждения обязателен',
      });
    }

    // Если email передан в запросе, сохраняем его в сессии для проверки кода
    if (email && !req.session.pendingEmail) {
      req.session.pendingEmail = email.toLowerCase();
    }

    // Нужен email в сессии для проверки кода
    if (!req.session.pendingEmail) {
      return res.status(400).json({
        success: false,
        error: 'Email не найден в сессии. Пожалуйста, запросите код подтверждения снова.',
      });
    }

    // Сохраняем гостевые ID до обработки
    const guestId = req.session.guestId;
    const previousGuestId = req.session.previousGuestId;

    // 1. Проверяем сам код верификации
    const codeVerificationResult = await verificationService.verifyCode(
      code,
      'email',
      req.session.pendingEmail
    );

    if (!codeVerificationResult.success) {
      return res.status(400).json({
        success: false,
        error: codeVerificationResult.error || 'Неверный код подтверждения',
      });
    }

    // 2. Обрабатываем аутентификацию/привязку и проверяем роль через AuthService
    const authResult = await authService.handleEmailVerification(
      req.session.pendingEmail, // Передаем email из сессии
      req.session // Передаем всю сессию
    );

    // ---> ДОБАВЛЯЕМ ПОЛУЧЕНИЕ И СОХРАНЕНИЕ АДРЕСА КОШЕЛЬКА В СЕССИЮ <---
    let linkedWalletAddress = null;
    if (authResult.userId) {
      try {
        const walletIdentity = await identityService.findIdentity(authResult.userId, 'wallet');
        if (walletIdentity) {
            linkedWalletAddress = walletIdentity.provider_id;
        }
      } catch (walletError) {
        logger.warn(`[email/verify-code] Could not fetch linked wallet for user ${authResult.userId}:`, walletError);
      }
    }
    // ---> КОНЕЦ ДОБАВЛЕНИЯ <---

    // ---> ОПРЕДЕЛЯЕМ РОЛЬ НА ОСНОВЕ БАЛАНСА ПРИВЯЗАННОГО КОШЕЛЬКА <---
    let finalIsAdmin = false; // Роль по умолчанию
    if (linkedWalletAddress) {
        try {
            const userAccessLevel = await authService.getUserAccessLevel(linkedWalletAddress);
            // Используем роль из userAccessLevel, которая уже правильно определена с учетом порогов
            const newRole = userAccessLevel.level;
            
            logger.info(`[email/verify-code] Role determined for ${linkedWalletAddress}: ${newRole} (tokens: ${userAccessLevel.tokenCount})`);

            // Обновляем роль в БД, если она отличается от текущей
            if (authResult.role !== newRole) {
                await db.getQuery()('UPDATE users SET role = $1 WHERE id = $2', [newRole, authResult.userId]);
                logger.info(`[email/verify-code] User role updated in DB for user ${authResult.userId} to ${newRole}`);
            }
            finalIsAdmin = (newRole === ROLES.EDITOR || newRole === ROLES.READONLY);
        } catch (tokenCheckError) {
            logger.error(`[email/verify-code] Error checking tokens for ${linkedWalletAddress}:`, tokenCheckError);
            // В случае ошибки проверки токенов, используем роль из authResult
            finalIsAdmin = (authResult.role === 'editor' || authResult.role === 'readonly');
        }
    } else {
        // Если кошелек не привязан, используем роль из authResult (вероятно, 'user')
        finalIsAdmin = (authResult.role === 'editor' || authResult.role === 'readonly');
        logger.info(`[email/verify-code] No linked wallet found for user ${authResult.userId}. Using role from authResult: ${authResult.role}`);
    }
    // ---> КОНЕЦ ОПРЕДЕЛЕНИЯ РОЛИ <---

    // 3. Устанавливаем сессию на основе результата
    req.session.userId = authResult.userId;
    req.session.authenticated = true;
    req.session.authType = 'email';
    req.session.email = authResult.email;
    req.session.userAccessLevel = finalIsAdmin ? { level: 'editor', tokenCount: 0, hasAccess: true } : { level: 'user', tokenCount: 0, hasAccess: false }; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА
    // ---> ДОБАВЛЯЕМ АДРЕС КОШЕЛЬКА В СЕССИЮ <---
    if (linkedWalletAddress) {
      req.session.address = linkedWalletAddress;
    }
    // ---> КОНЕЦ ДОБАВЛЕНИЯ <---

    // Восстанавливаем/обновляем гостевые ID в сессии, если они были
    if (guestId) req.session.guestId = guestId;
    if (previousGuestId) req.session.previousGuestId = previousGuestId;

    // Очищаем временные данные (authService уже должен был это сделать, но на всякий случай)
    delete req.session.tempUserId;
    delete req.session.pendingEmail;

    // Сохраняем обновленную сессию
    await sessionService.saveSession(req.session);

    // Связываем гостевые сообщения
    await sessionService.linkGuestMessages(req.session, authResult.userId);

    // 4. Отправляем ответ
    // Получаем уровень доступа для пользователя
    let userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
    if (linkedWalletAddress) {
      userAccessLevel = await authService.getUserAccessLevel(linkedWalletAddress);
    }

    return res.json({
      success: true,
      userId: authResult.userId,
      email: authResult.email,
      userAccessLevel: userAccessLevel, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНЫЙ УРОВЕНЬ ДОСТУПА
      authenticated: true,
      isNewAuth: authResult.isNewUser,
      address: linkedWalletAddress || null // <-- ВОЗВРАЩАЕМ АДРЕС КОШЕЛЬКА
    });

  } catch (error) {
    logger.error('[email/verify-code] Error:', error);
    // Проверяем, является ли ошибка созданной нами в authService
    const errorMessage = error.message === 'Ошибка обработки верификации Email'
      ? error.message
      : 'Ошибка сервера';
    return res.status(500).json({
      success: false,
      error: errorMessage,
    });
  }
});

// Инициализация Telegram аутентификации
router.post('/telegram/init', async (req, res) => {
  try {
    // Инициализируем процесс аутентификации через Telegram, передавая сессию
    // и получаем результат (код и ссылку на бота)
    const result = await initTelegramAuth(req.session);



    // Сохраняем сессию, чтобы guestId точно записался в базу данных
    await sessionService.saveSession(req.session);

    // Возвращаем код и ссылку на бота на фронтенд
    res.json({
      success: true,
      message: 'Проверьте вашего Telegram бота',
      verificationCode: result.verificationCode,
      botLink: result.botLink,
    });
  } catch (error) {
    logger.error('Error initializing Telegram auth:', error);

    if (error.message === 'Telegram уже привязан к этому аккаунту') {
      return res.status(400).json({
        success: false,
        error: error.message,
      });
    }

    res.status(500).json({
      success: false,
      error: 'Failed to initialize Telegram auth',
    });
  }
});

// Инициализация email аутентификации
router.post('/email/init', async (req, res) => {
  try {
    const { email } = req.body;

    if (!email || !email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
      return res.status(400).json({
        success: false,
        error: 'Некорректный формат email',
      });
    }

    // Инициализация email аутентификации
    const result = await emailAuth.initEmailAuth(req.session, email);

    // Сохраняем сессию
    await sessionService.saveSession(req.session);

    return res.json({
      success: true,
      message: 'Код верификации отправлен на email',
    });
  } catch (error) {
    logger.error('Error in email auth initialization:', error);
    res.status(500).json({
      success: false,
      error: 'Внутренняя ошибка сервера',
    });
  }
});

// Проверка статуса аутентификации
router.get('/check', async (req, res) => {
  try {
    const authenticated = req.session.authenticated || false;
    const authType = req.session.authType || null;

    let identities = [];
    let userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };

    if (authenticated && req.session.userId) {
      // Если пользователь аутентифицирован, получаем его идентификаторы из БД
      try {
        identities = await identityService.getUserIdentities(req.session.userId);

        // Для пользователей с кошельком проверяем токены в реальном времени
        if (authType === 'wallet' && req.session.address) {
          userAccessLevel = await authService.getUserAccessLevel(req.session.address);
          logger.info(`[auth/check] Access level for wallet ${req.session.address}:`, userAccessLevel);
        } else {
          // Для других типов аутентификации используем роль из БД
          const roleResult = await db.getQuery()('SELECT role FROM users WHERE id = $1', [
            req.session.userId,
          ]);

          if (roleResult.rows.length > 0) {
            const role = roleResult.rows[0].role;
            // Преобразуем старую роль в новый формат
            // Определяем userAccessLevel на основе роли
            if (role === 'editor') {
              userAccessLevel = { level: 'editor', tokenCount: 5999998, hasAccess: true };
            } else if (role === 'readonly') {
              userAccessLevel = { level: 'readonly', tokenCount: 100, hasAccess: true };
            } else {
              userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
            }
          }
        }
        
        req.session.userAccessLevel = userAccessLevel;
      } catch (error) {
        logger.error(`[session/check] Error fetching identities: ${error.message}`);
      }
    }

    // Проверяем, нужно ли создать новый гостевой ID
    if (!authenticated && !req.session.guestId) {
      req.session.guestId = crypto.randomBytes(16).toString('hex');

      // Сохраняем сессию с новым гостевым ID
      await sessionService.saveSession(req.session);
    }

    // Формируем ответ
    const response = {
      success: true,
      authenticated,
      userId: req.session.userId || null,
      guestId: req.session.guestId || null,
      authType,
      identitiesCount: identities.length,
      userAccessLevel: userAccessLevel,
    };

    // Добавляем специфические поля в зависимости от типа аутентификации
    if (authType === 'wallet') {
      response.address = req.session.address || null;
    } else if (authType === 'email') {
      response.email = req.session.email || null;
    } else if (authType === 'telegram') {
      response.telegramId = req.session.telegramId || null;
      if (req.session.telegramUsername) {
        response.telegramUsername = req.session.telegramUsername;
      }
      if (req.session.telegramFirstName) {
        response.telegramFirstName = req.session.telegramFirstName;
      }
    }

    return res.json(response);
  } catch (error) {
    logger.error('[session/check] Error:', error);
    return res.status(500).json({
      success: false,
      error: 'Internal server error',
    });
  }
});

// Выход из системы
router.post('/logout', async (req, res) => {
  try {
    // Очищаем все идентификаторы сессии
    req.session.authenticated = false;
    req.session.userId = null;
    req.session.address = null;
    req.session.telegramId = null;
    req.session.email = null;
    req.session.userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
    req.session.guestId = null;
    req.session.previousGuestId = null;
    req.session.processedGuestIds = [];
    req.session.pendingEmail = null;
    req.session.authType = null;

    // Сохраняем изменения в сессии
    await sessionService.saveSession(req.session);

    // Уничтожаем сессию полностью
    req.session.destroy((err) => {
      if (err) {
        logger.error('[logout] Error destroying session:', err);
        return res.status(500).json({ success: false, error: 'Error during logout' });
      }
      res.clearCookie('connect.sid');
      res.json({ success: true, message: 'Logged out successfully' });
    });
  } catch (error) {
    logger.error('[logout] Error:', error);
    res.status(500).json({ success: false, error: 'Internal server error during logout' });
  }
});

// Маршрут для проверки и обновления статуса администратора
router.get('/check-access', requireAuth, async (req, res) => {
  try {
    const userId = req.session.userId;
    const address = req.session.address;

    if (address) {
      const userAccessLevel = await authService.getUserAccessLevel(address);

      // Обновляем сессию
      req.session.userAccessLevel = userAccessLevel;
      await sessionService.saveSession(req.session);

      return res.json({
        success: true,
        userAccessLevel,
        userId,
        address,
      });
    }

    return res.json({
      success: true,
      userAccessLevel: { level: 'user', tokenCount: 0, hasAccess: false },
      userId,
      address: null,
    });
  } catch (error) {
    logger.error('Error checking access:', error);
    return res.status(500).json({ error: 'Internal server error' });
  }
});

// Обновление сессии
router.post('/refresh-session', async (req, res) => {
  try {
    const { address } = req.body;

    if (req.session && req.session.authenticated) {
      logger.info('Обновление сессии для пользователя:', req.session.userId);

      // Обновляем время жизни сессии
      req.session.cookie.maxAge = 30 * 24 * 60 * 60 * 1000; // 30 дней

      // Сохраняем обновленную сессию
      await sessionService.saveSession(req.session);

      return res.json({ success: true });
    } else if (address) {
      // Если сессия не аутентифицирована, но есть адрес
      try {
        const user = await identityService.findUserByIdentity('wallet', address.toLowerCase());

        if (user) {
          // Обновляем сессию
          req.session.authenticated = true;
          req.session.userId = user.id;
          req.session.address = address.toLowerCase();
          let userAccessLevel;
          if (user.role === 'editor') {
            userAccessLevel = { level: 'editor', tokenCount: 5999998, hasAccess: true };
          } else if (user.role === 'readonly') {
            userAccessLevel = { level: 'readonly', tokenCount: 100, hasAccess: true };
          } else {
            userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
          }
          req.session.userAccessLevel = userAccessLevel;
          req.session.authType = 'wallet';

          // Сохраняем обновленную сессию
          await sessionService.saveSession(req.session);

          return res.json({ success: true });
        }
      } catch (error) {
        logger.error('Ошибка при проверке пользователя:', error);
      }
    }

    // Если не удалось обновить сессию, возвращаем успех=false, но не ошибку
    return res.json({ success: false });
  } catch (error) {
    logger.error('Ошибка при обновлении сессии:', error);
    res.status(500).json({ error: 'Ошибка сервера' });
  }
});

// Аутентификация через wallet
router.post('/wallet', async (req, res) => {
  try {
    const { address, nonce, signature } = req.body;

    if (!address || !nonce || !signature) {
      return res.status(400).json({
        success: false,
        error: 'Missing required fields',
      });
    }

    // Сохраняем гостевые ID до аутентификации
    const guestId = req.session.guestId;
    const previousGuestId = req.session.previousGuestId;

    // Формируем сообщение для проверки
    const message = `Sign this message to authenticate with HB3 DApp: ${nonce}`;

    // Проверяем подпись
    const validSignature = await authService.verifySignature(message, signature, address);
    if (!validSignature) {
      return res.status(401).json({
        success: false,
        error: 'Invalid signature',
      });
    }

    // Получаем или создаем пользователя
    const { userId } = await authService.findOrCreateUser(address);

    // Проверяем наличие админских токенов
    const userAccessLevel = await authService.getUserAccessLevel(address);

    // Обновляем роль пользователя в базе данных, если нужно
    if (userAccessLevel.hasAccess) {
      await db.getQuery()('UPDATE users SET role = $1 WHERE id = $2', ['editor', userId]);
    }

    // Сохраняем идентификаторы
    await identityService.saveIdentity(userId, 'wallet', address.toLowerCase(), true);

    if (guestId) {
      await identityService.saveIdentity(userId, 'guest', guestId, true);
    }

    if (previousGuestId && previousGuestId !== guestId) {
      await identityService.saveIdentity(userId, 'guest', previousGuestId, true);
    }

    // Устанавливаем сессию
    req.session.userId = userId;
    req.session.address = address.toLowerCase();
    req.session.authType = 'wallet';
    req.session.authenticated = true;
    req.session.userAccessLevel = userAccessLevel;

    // Сохраняем сессию
    await sessionService.saveSession(req.session);

    // Связываем гостевые сообщения с пользователем
    await sessionService.linkGuestMessages(req.session, userId);

    // Возвращаем успешный ответ
    return res.json({
      success: true,
      userId,
      address,
      userAccessLevel,
      authenticated: true,
    });
  } catch (error) {
    logger.error('[wallet] Error:', error);
    res.status(500).json({
      success: false,
      error: 'Server error during wallet authentication',
    });
  }
});

// Маршрут для получения всех идентификаторов пользователя
router.get('/identities', requireAuth, async (req, res) => {
  try {
    const { userId } = req.session;

    // Получаем все идентификаторы пользователя
    const identities = await identityService.getUserIdentities(userId);

    res.json({
      success: true,
      identities,
    });
  } catch (error) {
    logger.error('Error getting user identities:', error);
    res.status(500).json({
      success: false,
      error: 'Internal server error',
    });
  }
});

// Маршрут для проверки и инициализации сессии гостя
router.get('/check-session', async (req, res) => {
  try {
    // Если у пользователя нет guestId, создаем его
    if (!req.session.guestId && !req.session.authenticated) {
      req.session.guestId = crypto.randomBytes(16).toString('hex');
      await sessionService.saveSession(req.session);
    }

    res.json({
      success: true,
      guestId: req.session.guestId,
      isAuthenticated: req.session.authenticated || false,
    });
  } catch (error) {
    logger.error('Error checking session:', error);
    res.status(500).json({
      success: false,
      error: 'Internal server error',
    });
  }
});

// Маршрут для проверки баланса токенов
router.get('/check-tokens/:address', async (req, res) => {
  try {
    const { address } = req.params;

    // Получаем балансы токенов с минимальными балансами
    const balances = await authService.getUserTokenBalances(address);

    res.json({
      success: true,
      data: balances,
    });
  } catch (error) {
    logger.error('Error checking token balances:', error);
    res.status(500).json({
      success: false,
      error: 'Internal server error',
    });
  }
});

// Маршрут для получения уровня доступа пользователя
router.get('/access-level/:address', async (req, res) => {
  try {
    const { address } = req.params;

    // Получаем уровень доступа пользователя
    const accessLevel = await authService.getUserAccessLevel(address);

    res.json({
      success: true,
      data: accessLevel,
    });
  } catch (error) {
    logger.error('Error getting user access level:', error);
    res.status(500).json({
      success: false,
      error: 'Internal server error',
    });
  }
});

/**
 * Подключение кошелька через токен связывания
 * Используется для привязки Telegram/Email идентификаторов к кошельку
 */
router.post('/wallet-with-link', authLimiter, async (req, res) => {
  try {
    const { address, signature, message, token } = req.body;

    if (!address || !signature || !message || !token) {
      return res.status(400).json({ 
        success: false,
        error: 'Требуются: address, signature, message, token' 
      });
    }

    // 1. Проверяем подпись
    let recoveredAddress;
    try {
      recoveredAddress = ethers.verifyMessage(message, signature);
    } catch (err) {
      logger.error('[Auth] Ошибка верификации подписи:', err);
      return res.status(400).json({ 
        success: false,
        error: 'Неверная подпись' 
      });
    }

    if (recoveredAddress.toLowerCase() !== address.toLowerCase()) {
      return res.status(400).json({ 
        success: false,
        error: 'Подпись не соответствует адресу' 
      });
    }

    // 2. Проверяем и используем токен
    const identityLinkService = require('../services/IdentityLinkService');
    const linkResult = await identityLinkService.useLinkToken(token, address);

    if (!linkResult.success) {
      return res.status(400).json({ 
        success: false,
        error: linkResult.error 
      });
    }

    const { userId, identifier, role } = linkResult;

    // 3. Мигрируем историю гостя
    const universalGuestService = require('../services/UniversalGuestService');
    const migrationResult = await universalGuestService.migrateToUser(identifier, userId);

    logger.info('[Auth] История мигрирована:', migrationResult);

    // 4. Обновляем сессию
    req.session.userId = userId;
    req.session.address = address.toLowerCase();
    req.session.authenticated = true;
    req.session.authType = 'wallet';
    const hasAccess = (role === 'editor' || role === 'readonly');
    req.session.userAccessLevel = hasAccess ? { level: role === 'editor' ? 'editor' : 'readonly', tokenCount: 0, hasAccess: true } : { level: 'user', tokenCount: 0, hasAccess: false };

    await sessionService.saveSession(req.session, 'wallet-with-link');

    logger.info(`[Auth] Кошелек подключен через токен: ${address} → user ${userId}`);

    res.json({ 
      success: true, 
      userId,
      role,
      conversationId: migrationResult.conversationId,
      migratedMessages: migrationResult.migrated,
      message: 'Кошелек успешно подключен, история перенесена'
    });

  } catch (error) {
    logger.error('[Auth] Ошибка в wallet-with-link:', error);
    res.status(500).json({ 
      success: false,
      error: 'Внутренняя ошибка сервера' 
    });
  }
});

// ✨ НОВОЕ: Получение прав доступа пользователя
router.get('/permissions', requireAuth, async (req, res) => {
  try {
    const userId = req.session.userId;
    
    // Получаем роль пользователя из БД
    const users = await encryptedDb.getData('users', { id: userId }, 1);
    const userRole = users && users.length > 0 ? users[0].role : 'user';
    
    // Получаем настройки прав через adminLogicService
    const adminLogicService = require('../services/adminLogicService');
    const permissions = adminLogicService.getAdminSettings({ role: userRole });
    
    res.json({
      success: true,
      userId: userId,
      permissions: permissions
    });
    
  } catch (error) {
    logger.error('[Auth] Ошибка получения permissions:', error);
    res.status(500).json({
      success: false,
      error: 'Ошибка получения прав доступа'
    });
  }
});

module.exports = router;
