# /opt/trueconf_bot/photo_bot/handlers.py
import os
import asyncio
import logging
import smtplib
import time
from datetime import datetime
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from PIL import Image
from trueconf import Router, Message
from trueconf.types import FSInputFile

import config.config as config
from utils import states
from utils.menu import MENU_TEXT
from photo_bot.photo_processor import prepare_ad_photo, get_crop_coordinates
from utils.texts import (
    EMOJI_DIGITS,
    PHOTO_MAIN_MENU_TEXT,
    system_error_text,
    photo_error_handling,
    PHOTO_PROCESSING_FACE_TEXT,
    PHOTO_UPLOADING_API_TEXT,
    PHOTO_AI_PROCESSING_TEXT,
    photo_success_published,
    photo_success_pending,
    photo_error_rejected,
    photo_error_already_pending,
    photo_cancel_text,
    photo_preview_ready,
)

# 🔌 Импортируем централизованную функцию сбора статистики из main
from utils.stats_logger import log_menu_stats

logger = logging.getLogger(__name__)
router = Router()

# Словарь для временного хранения путей к фото пользователей
# Формат: {user_id: {'path': '/tmp/orig_user.jpg', 'coords': (x1,y1,x2,y2)}}
pending_photos = {}

# =========================================================
# СИСТЕМА ОБРАБОТКИ ОШИБОК И ЛОГИРОВАНИЯ
# =========================================================
EMAIL_COOLDOWN_SEC = 10.0
last_email_time = 0.0

def log_and_notify_photo_error(user_id: str, action: str, error_details: str):
    """Записывает системную ошибку в лог-файл и отправляет email-алерт администраторам"""
    global last_email_time

    log_dir = os.path.dirname(os.path.abspath(__file__))
    os.makedirs(log_dir, exist_ok=True)
    log_file = os.path.join(log_dir, "photo_errors.log")

    current_time = time.time()
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_entry = f"[{timestamp}] User: {user_id} | Action: {action} | Error: {error_details}\n"

    with open(log_file, "a", encoding="utf-8") as f:
        f.write(log_entry)

    if current_time - last_email_time < EMAIL_COOLDOWN_SEC:
        with open(log_file, "a", encoding="utf-8") as f:
            f.write(f"[{timestamp}] ALERT: Email suppressed due to rate limiting.\n")
        return

    last_email_time = current_time

    try:
        msg = MIMEMultipart()
        msg['From'] = str(getattr(config, 'DEFAULT_EMAIL_FROM', 'bot@noreply.com'))

        to_emails = getattr(config, 'ALERTS_SUPPORT_EMAILS', 'admin@example.com')
        msg['To'] = ", ".join(to_emails) if isinstance(to_emails, list) else str(to_emails)

        msg['Subject'] = f"TrueConf Bot Error: Фото Профиль - {action}"

        body = (
            f"Обнаружена системная ошибка в модуле загрузки фото профиля.\n\n"
            f"Время: {timestamp}\n"
            f"Пользователь (ID): {user_id}\n"
            f"Действие: {action}\n\n"
            f"Детали ошибки:\n{error_details}\n\n"
            f"(Уведомления об ошибках ограничены: не чаще 1 раза в {EMAIL_COOLDOWN_SEC} сек.)"
        )
        msg.attach(MIMEText(body, 'plain', 'utf-8'))

        smtp_server = getattr(config, 'SMTP_SERVER', 'localhost')
        smtp_port = int(getattr(config, 'SMTP_PORT', 25))

        with smtplib.SMTP(smtp_server, smtp_port) as server:
            smtp_user = getattr(config, 'SMTP_USER', None)
            smtp_pass = getattr(config, 'SMTP_PASSWORD', None)
            if smtp_user and smtp_pass:
                server.login(smtp_user, smtp_pass)
            server.send_message(msg)
    except Exception as e:
        with open(log_file, "a", encoding="utf-8") as f:
            f.write(f"[{timestamp}] СБОЙ ОТПРАВКИ EMAIL: {e}\n")


async def handle_photo_error(msg: Message, user_id: str, action: str, error_details: str):
    """Вызывает системное логирование и выдает заглушку пользователю"""
    logger.error(f"🔥 Ошибка фото-бота для {user_id}, действие: {action}: {error_details}")
    await asyncio.to_thread(log_and_notify_photo_error, user_id, action, error_details)

    await msg.answer(photo_error_handling(), parse_mode="html")


# =========================================================
# ОСНОВНОЙ ОБРАБОТЧИК
# =========================================================
@router.message()
async def photo_module_handler(msg: Message):
    user_id = msg.from_user.id

    if states.get_state(user_id) != "PHOTO_MODE":
        return

    # Помечаем сообщение как обработанное
    msg.handled = True

    user_login = user_id.split('@')[0] if '@' in user_id else user_id
    msg_text = getattr(msg.content, "text", "").strip() if hasattr(msg.content, "text") else ""
    is_attachment = hasattr(msg.type, "name") and msg.type.name == "ATTACHMENT"

    cmd = msg_text.lower()

    # 🔄 НОРМАЛИЗАЦИЯ КНОПОК ВК-ЭМОДЗИ
    for raw_num, emoji_num in EMOJI_DIGITS.items():
        if cmd == emoji_num:
            cmd = raw_num
            break

    # --- ВЫХОД (Кнопки 0 и 9 возвращают в общее меню с очисткой кэша) ---
    if cmd in ["0", "9", "/start", "меню"]:
        log_menu_stats(user_id, "Photo Bot", "Выход в главное меню")
        states.clear_state(user_id)
        if user_id in pending_photos:
            photo_data = pending_photos[user_id]
            if os.path.exists(photo_data['path']):
                os.remove(photo_data['path'])
            if 'preview_path' in photo_data and os.path.exists(photo_data['preview_path']):
                os.remove(photo_data['preview_path'])
            del pending_photos[user_id]

        await msg.answer(MENU_TEXT, parse_mode="html")
        return

    # --- ПОДТВЕРЖДЕНИЕ ОТПРАВКИ (Кнопка 1) ---
    if not is_attachment and user_id in pending_photos:
        if cmd == "1":
            photo_data = pending_photos[user_id]
            original_path = photo_data['path']
            
            await msg.answer(PHOTO_UPLOADING_API_TEXT, parse_mode="html")
            await msg.answer(PHOTO_AI_PROCESSING_TEXT, parse_mode="html")

            try:
                # Отправляем фото через API
                result = await asyncio.to_thread(
                    prepare_ad_photo, original_path, user_login
                )
                
                if result["success"]:
                    verdict = result.get("verdict")
                    if verdict == "published":
                        log_menu_stats(user_id, "Photo Bot", "Фото опубликовано")
                        await msg.answer(photo_success_published(), parse_mode="html")
                    elif verdict == "pending_moderation":
                        log_menu_stats(user_id, "Photo Bot", "Фото на модерации")
                        await msg.answer(photo_success_pending(), parse_mode="html")
                    else:
                        msg_text = result.get("message", "Фото обработано")
                        await msg.answer(f"✅ {msg_text}", parse_mode="html")
                else:
                    # Любая ошибка API — системная заглушка
                    await msg.answer(photo_error_handling(), parse_mode="html")
            except Exception as e:
                await handle_photo_error(msg, user_id, "Отправка фото через API", str(e))
            
            # Убираем за собой
            if os.path.exists(original_path):
                os.remove(original_path)
            if 'preview_path' in photo_data and os.path.exists(photo_data['preview_path']):
                os.remove(photo_data['preview_path'])
            states.clear_state(user_id)
            if user_id in pending_photos:
                del pending_photos[user_id]
            
            await asyncio.sleep(0.5)
            await msg.answer(MENU_TEXT, parse_mode="html")
            return

        # --- ОТМЕНА ФОТО (Кнопка 2) ---
        elif cmd == "2":
            log_menu_stats(user_id, "Photo Bot", "Отмена загруженного фото")
            photo_data = pending_photos[user_id]
            original_path = photo_data['path']
            if os.path.exists(original_path):
                os.remove(original_path)
            if 'preview_path' in photo_data and os.path.exists(photo_data['preview_path']):
                os.remove(photo_data['preview_path'])
            del pending_photos[user_id]
            states.clear_state(user_id)
            await msg.answer(photo_cancel_text(), parse_mode="html")
            return

        # --- ИСПРАВЛЕНО: Защита от мусорного ввода при висящем превью ---
        else:
            await msg.answer(system_error_text(EMOJI_DIGITS), parse_mode="html")
            return

    # --- ПРИЕМ НОВОГО ФОТО ---
    if is_attachment:
        file_id = getattr(msg.content, "file_id", None)
        raw_bytes = None

        await msg.answer(PHOTO_PROCESSING_FACE_TEXT, parse_mode="html")

        try:
            downloaded_file = await states.tc_bot.download_file_by_id(file_id)
            logger.info(f"Скачан файл для {user_login}: type={type(downloaded_file)}, len={len(downloaded_file) if isinstance(downloaded_file, (bytes, str)) else 'N/A'}")
            
            # Скачиваем в байты напрямую
            if isinstance(downloaded_file, bytes):
                raw_bytes = downloaded_file
            elif isinstance(downloaded_file, str) and os.path.exists(downloaded_file):
                with open(downloaded_file, 'rb') as f:
                    raw_bytes = f.read()
            else:
                # Пробуем как путь
                raw_path = downloaded_file if isinstance(downloaded_file, str) else None
                if raw_path and os.path.exists(raw_path):
                    with open(raw_path, 'rb') as f:
                        raw_bytes = f.read()
                else:
                    raise Exception(f"Не удалось получить байты файла: {type(downloaded_file)}")
            
            logger.info(f"Прочитано {len(raw_bytes)} байт для {user_login}")
            
            # Ищем лицо и получаем координаты
            coords = await asyncio.to_thread(get_crop_coordinates, raw_bytes)
            logger.info(f"get_crop_coordinates вернул: {coords} для {user_login}")
            
            if not coords:
                await msg.answer(
                    "❌ Лицо не найдено. Пожалуйста, сделайте фото анфас при хорошем освещении.\n\n"
                    f"{EMOJI_DIGITS['0']} — В главное меню",
                    parse_mode="html"
                )
                return
            
            # Генерируем превью
            try:
                from PIL import Image
                import io
                img = Image.open(io.BytesIO(raw_bytes))
                if img.mode != 'RGB':
                    img = img.convert('RGB')
                
                x1, y1, x2, y2 = coords
                cropped = img.crop((x1, y1, x2, y2))
                
                # Ресайз до квадрата
                side = min(cropped.size[0], cropped.size[1])
                left = (cropped.size[0] - side) // 2
                top = (cropped.size[1] - side) // 2
                cropped = cropped.crop((left, top, left + side, top + side))
                
                preview = cropped.resize((400, 400), Image.Resampling.LANCZOS)
                
                preview_path = f"/tmp/prev_{user_login}.jpg"
                preview.save(preview_path, format="JPEG", quality=85)
                
                preview_doc = FSInputFile(preview_path, filename="preview.jpg")
                await msg.answer_photo(preview_doc, preview_doc)
            except Exception as lib_err:
                await asyncio.to_thread(log_and_notify_photo_error, user_id, "Генерация превью", str(lib_err))
                raise Exception("Ошибка генерации превью")
            
            # Сохраняем оригинал и координаты
            original_path = f"/tmp/orig_{user_login}.jpg"
            with open(original_path, 'wb') as f:
                f.write(raw_bytes)
            
            pending_photos[user_id] = {
                'path': original_path,
                'coords': coords,
                'preview_path': preview_path
            }
            
            log_menu_stats(user_id, "Photo Bot", "Загрузка и обработка нового фото")
            
            await asyncio.sleep(0.5)
            await msg.answer(
                photo_preview_ready(),
                parse_mode="html"
            )
        except Exception as e:
            logger.error(f"🔥 Полная ошибка: {e}", exc_info=True)
            await handle_photo_error(msg, user_id, "Скачивание и обработка файла", str(e))
        return
