"""
Celery задачи для домашних заданий.
"""
from celery import shared_task
from django.utils import timezone
from datetime import timedelta
import logging

logger = logging.getLogger(__name__)


def _student_display_name(submission):
    """Имя ученика (только имя, без фамилии) — тот, кто отправил ДЗ."""
    if not submission or not getattr(submission, 'student', None):
        return None
    s = submission.student
    name = (s.first_name or (s.get_short_name() if getattr(s, 'email', None) else '') or '').strip()
    return name or f"Студент (id: {s.pk})"


@shared_task
def send_homework_deadline_reminders():
    """
    Отправка напоминаний о приближающихся дедлайнах домашних заданий.
    
    Запускается каждый день в 09:00.
    Отправляет напоминания за 1 день, 3 дня и 1 неделю до дедлайна.
    """
    from .models import Homework
    from apps.notifications.services import NotificationService
    
    now = timezone.now()
    
    # Находим задания с дедлайнами в ближайшие периоды
    deadlines_to_check = [
        (now + timedelta(days=1), 'Через 1 день'),   # Завтра
        (now + timedelta(days=3), 'Через 3 дня'),    # Через 3 дня
        (now + timedelta(days=7), 'Через неделю'),   # Через неделю
    ]
    
    sent_count = 0
    
    for deadline_date, deadline_text in deadlines_to_check:
        # Находим задания с дедлайном в этот день (в пределах дня)
        start_of_day = deadline_date.replace(hour=0, minute=0, second=0, microsecond=0)
        end_of_day = deadline_date.replace(hour=23, minute=59, second=59, microsecond=999999)
        
        homeworks = Homework.objects.filter(
            status='published',
            deadline__gte=start_of_day,
            deadline__lte=end_of_day
        ).select_related('mentor', 'lesson').prefetch_related('assigned_to', 'submissions')
        
        for homework in homeworks:
            # Оптимизация: используем prefetch_related для submissions и assigned_to
            # Преобразуем в list для использования предзагруженных данных
            submissions_list = list(homework.submissions.all())
            assigned_students_list = list(homework.assigned_to.all())
            submitted_student_ids = {sub.student_id for sub in submissions_list}
            students_without_submission = [
                student for student in assigned_students_list
                if student.id not in submitted_student_ids
            ]
            
            for student in students_without_submission:
                try:
                    NotificationService.create_notification_with_telegram(
                        recipient=student,
                        notification_type='homework_deadline_reminder',
                        title='⏰ Напоминание о дедлайне',
                        message=f'Домашнее задание "{homework.title}" нужно сдать {deadline_text}',
                        priority='normal',
                        action_url=f'/homework/{homework.id}/',
                        content_object=homework
                    )
                    sent_count += 1
                except Exception as e:
                    logger.error(f"Ошибка отправки напоминания о дедлайне: {str(e)}")
    
    logger.info(f"Отправлено {sent_count} напоминаний о дедлайнах домашних заданий")
    return f"Отправлено {sent_count} напоминаний о дедлайнах"


@shared_task
def auto_check_homework_submissions():
    """
    Автоматическая проверка домашних заданий через AI (если включена).
    
    Запускается каждые 30 минут.
    Проверяет решения, у которых включена автоматическая проверка.
    """
    from .models import HomeworkSubmission
    from .ai_service import get_ai_service
    
    # Находим решения с включенной автоматической проверкой
    submissions = HomeworkSubmission.objects.filter(
        homework__auto_check_enabled=True,
        homework__ai_check_enabled=True,
        status='pending',
        ai_checked_at__isnull=True
    ).select_related('homework', 'student')[:10]  # Ограничиваем количество за раз
    
    checked_count = 0
    
    for submission in submissions:
        try:
            # Получаем файлы решения
            submission_files = []
            if submission.attachment:
                submission_files.append(submission.attachment.name)
            
            from .models import HomeworkFile
            # Оптимизация: используем values_list для получения только имен файлов
            additional_file_names = HomeworkFile.objects.filter(
                submission=submission,
                file_type='submission'
            ).exclude(file='').values_list('file', flat=True)
            submission_files.extend([name for name in additional_file_names if name])
            
            # Вызываем AI проверку
            ai_service = get_ai_service()
            result = ai_service.check_submission(
                homework_title=submission.homework.title,
                homework_description=submission.homework.description,
                homework_max_score=submission.homework.max_score,
                submission_content=submission.content or '',
                submission_files=submission_files,
                student_name=_student_display_name(submission),
            )
            
            if result.get('success'):
                # Сохраняем результат AI проверки
                submission.ai_score = result.get('score')
                submission.ai_feedback = result.get('feedback')
                submission.ai_checked_at = timezone.now()
                submission.status = 'checking'  # Переводим в статус "на проверке"
                submission.save(update_fields=['ai_score', 'ai_feedback', 'ai_checked_at', 'status'])
                checked_count += 1
                
                logger.info(f"Автоматически проверено решение ДЗ {submission.id} через AI. Оценка: {submission.ai_score}")
        
        except Exception as e:
            logger.error(f"Ошибка автоматической проверки решения ДЗ {submission.id}: {str(e)}", exc_info=True)
    
    if checked_count > 0:
        logger.info(f"Автоматически проверено {checked_count} решений домашних заданий")
    
    return f"Автоматически проверено {checked_count} решений"


@shared_task(bind=True)
def run_mentor_ai_check_submission(self, submission_id, publish):
    """
    Проверка решения ДЗ через AI по настройкам ментора (доверять AI).
    Вызывается после загрузки ДЗ студентом, если у ментора включено ai_trust_draft или ai_trust_publish.
    publish: True — выставить оценку и опубликовать (status=graded, уведомление студенту);
             False — сохранить только как черновик (ai_score, ai_feedback, ai_checked_at).
    """
    import traceback
    from .models import HomeworkSubmission, HomeworkFile
    from .ai_service import get_ai_service
    from django.core.files.storage import default_storage
    from apps.users.cache_utils import invalidate_dashboard_cache
    from apps.notifications.services import NotificationService

    logger.info("run_mentor_ai_check_submission: старт submission_id=%s publish=%s", submission_id, publish)
    try:
        submission = HomeworkSubmission.objects.select_related(
            'homework', 'homework__mentor', 'student'
        ).prefetch_related(
            'homework__assignment_files'
        ).get(pk=submission_id)
    except HomeworkSubmission.DoesNotExist:
        logger.warning("run_mentor_ai_check_submission: submission %s не найден", submission_id)
        return

    try:
        mentor = submission.homework.mentor
        homework_files = []
        homework_file_paths = []
        homework_file_contents = []
        def _add_homework_file(name):
            homework_files.append(name)
            try:
                p = default_storage.path(name)
                if p:
                    homework_file_paths.append(p)
                    return
            except Exception:
                pass
            try:
                with default_storage.open(name, 'rb') as f:
                    data = f.read(2 * 1024 * 1024 + 1)
                fname = name.split('/')[-1] if '/' in name else name
                homework_file_contents.append((fname, data[: 2 * 1024 * 1024]))
            except Exception:
                pass
        if submission.homework.attachment:
            _add_homework_file(submission.homework.attachment.name)
        for f in submission.homework.assignment_files.all():
            if f.file:
                _add_homework_file(f.file.name)
        submission_files = []
        submission_file_paths = []
        submission_file_contents = []
        def _add_submission_file(name):
            submission_files.append(name)
            try:
                p = default_storage.path(name)
                if p:
                    submission_file_paths.append(p)
                    return
            except Exception:
                pass
            try:
                with default_storage.open(name, 'rb') as f:
                    data = f.read(2 * 1024 * 1024 + 1)
                fname = name.split('/')[-1] if '/' in name else name
                submission_file_contents.append((fname, data[: 2 * 1024 * 1024]))
            except Exception:
                pass
        if submission.attachment:
            _add_submission_file(submission.attachment.name)
        for file_obj in HomeworkFile.objects.filter(submission=submission, file_type='submission'):
            if file_obj.file:
                _add_submission_file(file_obj.file.name)

        ai_service = get_ai_service()
        result = ai_service.check_submission(
            homework_title=submission.homework.title,
            homework_description=submission.homework.description or '',
            homework_max_score=5,
            submission_content=submission.content or '',
            submission_files=submission_files,
            homework_files=homework_files,
            homework_file_paths=homework_file_paths,
            submission_file_paths=submission_file_paths,
            homework_file_contents=homework_file_contents,
            submission_file_contents=submission_file_contents,
            student_name=_student_display_name(submission),
        )

        if not result.get('success'):
            logger.warning(
                "run_mentor_ai_check_submission: AI проверка не удалась для submission %s: %s",
                submission_id, result.get('error', '')
            )
            return

        student_name = _student_display_name(submission)
        homework_title = submission.homework.title

        skipped_reason = result.get('skipped_reason')
        if skipped_reason:
            # Текст не удалось извлечь — сохраняем черновик, запрос к AI не отправляли
            submission.ai_score = None
            submission.ai_feedback = result.get('feedback', '')
            submission.ai_checked_at = timezone.now()
            submission.save(update_fields=['ai_score', 'ai_feedback', 'ai_checked_at'])
            invalidate_dashboard_cache(mentor.id, 'mentor')
            NotificationService.create_notification_with_telegram(
                recipient=mentor,
                notification_type='homework_submitted',
                title='⚠️ ИИ не смог прочитать задание или решение',
                message=f'{student_name} — ДЗ «{homework_title}»: не удалось извлечь текст из файлов. Проверьте вручную или добавьте текст/.txt.',
                priority='normal',
                action_url=f'/homework/{submission.homework.id}/submissions/{submission.id}/',
                content_object=submission
            )
            logger.info("run_mentor_ai_check_submission: submission %s — пропуск AI (skipped_reason=%s)", submission_id, skipped_reason)
            return

        score = result.get('score')
        feedback = result.get('feedback', '')
        score = max(1, min(5, score)) if score is not None else None
        if score is None:
            logger.warning("run_mentor_ai_check_submission: submission %s — AI вернул пустую оценку", submission_id)
            return

        if publish:
            submission.grade(score, feedback, checked_by=mentor)
            submission.graded_by_ai = True
            submission.save(update_fields=['graded_by_ai'])
            invalidate_dashboard_cache(submission.student.id, 'client')
            invalidate_dashboard_cache(mentor.id, 'mentor')
            msg_student = f'Проверено ДЗ "{homework_title}". Оценка: {score}/5'
            if feedback and str(feedback).strip():
                comment = (feedback[:500] + '…') if len(feedback) > 500 else feedback
                msg_student += f'\n\n💬 Комментарий:\n{comment}'
            NotificationService.create_notification_with_telegram(
                recipient=submission.student,
                notification_type='homework_reviewed',
                title='✅ ДЗ проверено',
                message=msg_student,
                priority='normal',
                action_url=f'/homework/{submission.homework.id}/submissions/{submission.id}/',
                content_object=submission
            )
            NotificationService.create_notification_with_telegram(
                recipient=mentor,
                notification_type='homework_reviewed',
                title='🤖 ИИ проверил ДЗ и выставил оценку',
                message=f'{student_name} — ДЗ «{homework_title}»: оценка {score}/5. ИИ поставил оценку и опубликовал результат.',
                priority='normal',
                action_url=f'/homework/{submission.homework.id}/submissions/{submission.id}/',
                content_object=submission
            )
            logger.info("run_mentor_ai_check_submission: submission %s опубликована AI, оценка %s", submission_id, score)
        else:
            submission.ai_score = score
            submission.ai_feedback = feedback
            submission.ai_checked_at = timezone.now()
            submission.save(update_fields=['ai_score', 'ai_feedback', 'ai_checked_at'])
            invalidate_dashboard_cache(mentor.id, 'mentor')
            # Формируем сообщение с комментарием ИИ (HTML форматирование для Telegram)
            feedback_preview = feedback[:400] + "..." if len(feedback) > 400 else feedback
            # Экранируем HTML символы в комментарии
            import html
            feedback_escaped = html.escape(feedback_preview)
            message_text = (
                f'{student_name} — ДЗ «{homework_title}»\n\n'
                f'🤖 <b>Предварительная проверка ИИ:</b>\n'
                f'⭐ Оценка: {score}/5\n\n'
                f'💬 <b>Комментарий ИИ:</b>\n<i>{feedback_escaped}</i>\n\n'
                f'📝 Сохранено как черновик.\n\n'
                f'В боте нажмите «Домашние задания» → выберите это задание — там кнопки «Редактировать ответ» и «Сохранить ответ».'
            )
            NotificationService.create_notification_with_telegram(
                recipient=mentor,
                notification_type='homework_submitted',
                title='🤖 ИИ проверил ДЗ, статус: черновик',
                message=message_text,
                priority='normal',
                action_url=f'/homework/{submission.homework.id}/submissions/{submission.id}/',
                content_object=submission
            )
            logger.info("run_mentor_ai_check_submission: submission %s сохранена как черновик AI, оценка %s", submission_id, score)
    except Exception as e:
        logger.exception(
            "run_mentor_ai_check_submission: ошибка для submission_id=%s: %s\n%s",
            submission_id, e, traceback.format_exc()
        )
        raise


@shared_task
def cleanup_old_homework_data():
    """
    Очистка старых данных домашних заданий.
    
    Запускается каждый месяц 1-го числа в 05:00.
    Архивирует старые задания и удаляет старые файлы.
    """
    from .models import Homework
    from django.utils import timezone
    from datetime import timedelta
    
    # Архивируем задания старше 1 года без активности
    one_year_ago = timezone.now() - timedelta(days=365)
    
    old_homeworks = Homework.objects.filter(
        status='published',
        updated_at__lt=one_year_ago,
        submissions__isnull=True  # Без решений
    )
    
    archived_count = old_homeworks.update(status='archived')
    
    logger.info(f"Архивировано {archived_count} старых домашних заданий")
    return f"Архивировано {archived_count} старых домашних заданий"


@shared_task
def update_homework_statistics():
    """
    Обновление статистики домашних заданий.
    
    Запускается каждый день в 02:00.
    Пересчитывает статистику для всех активных заданий.
    """
    from .models import Homework
    
    # Находим все опубликованные задания
    homeworks = Homework.objects.filter(status='published')
    
    updated_count = 0
    for homework in homeworks:
        try:
            homework.update_statistics()
            updated_count += 1
        except Exception as e:
            logger.error(f"Ошибка обновления статистики для ДЗ {homework.id}: {str(e)}")
    
    logger.info(f"Обновлена статистика для {updated_count} домашних заданий")
    return f"Обновлена статистика для {updated_count} домашних заданий"


@shared_task
def check_overdue_homeworks():
    """
    Проверка просроченных домашних заданий и отправка уведомлений.
    
    Запускается каждый день в 08:00.
    Отправляет уведомления студентам о просроченных заданиях.
    """
    from .models import Homework
    from apps.notifications.services import NotificationService
    
    now = timezone.now()
    
    # Находим просроченные опубликованные задания
    overdue_homeworks = Homework.objects.filter(
        status='published',
        deadline__lt=now
    ).select_related('mentor', 'lesson').prefetch_related('assigned_to', 'submissions')
    
    sent_count = 0
    
    for homework in overdue_homeworks:
        # Оптимизация: используем prefetch_related для submissions
        submitted_student_ids = {sub.student_id for sub in homework.submissions.all()}
        students_without_submission = [
            student for student in homework.assigned_to.all()
            if student.id not in submitted_student_ids
        ]
        
        for student in students_without_submission:
            try:
                NotificationService.create_notification_with_telegram(
                    recipient=student,
                    notification_type='homework_overdue',
                    title='⚠️ Просрочено домашнее задание',
                    message=f'Просрочено домашнее задание "{homework.title}". Дедлайн: {homework.deadline.strftime("%d.%m.%Y %H:%M")}',
                    priority='high',
                    action_url=f'/homework/{homework.id}/',
                    content_object=homework
                )
                sent_count += 1
            except Exception as e:
                logger.error(f"Ошибка отправки уведомления о просроченном ДЗ: {str(e)}")
    
    logger.info(f"Отправлено {sent_count} уведомлений о просроченных домашних заданиях")
    return f"Отправлено {sent_count} уведомлений о просроченных заданиях"


@shared_task
def cleanup_old_files():
    """
    Очистка старых неиспользуемых файлов домашних заданий.
    
    Запускается каждую неделю в воскресенье в 02:00.
    Удаляет файлы из архивированных заданий старше 2 лет.
    """
    from .models import HomeworkFile
    from django.utils import timezone
    from datetime import timedelta
    import os
    
    two_years_ago = timezone.now() - timedelta(days=730)
    
    # Находим файлы из архивированных заданий старше 2 лет
    old_files = HomeworkFile.objects.filter(
        homework__status='archived',
        homework__updated_at__lt=two_years_ago,
        created_at__lt=two_years_ago
    )
    
    deleted_count = 0
    # Оптимизация: сначала удаляем физические файлы, затем удаляем записи одним запросом
    old_files_list = list(old_files)
    file_ids_to_delete = []
    for file_obj in old_files_list:
        try:
            # Удаляем физический файл
            if file_obj.file and os.path.isfile(file_obj.file.path):
                os.remove(file_obj.file.path)
            file_ids_to_delete.append(file_obj.id)
        except Exception as e:
            logger.error(f"Ошибка удаления физического файла ДЗ {file_obj.id}: {str(e)}")
    
    # Удаляем записи из базы данных одним запросом
    if file_ids_to_delete:
        deleted_count = HomeworkFile.objects.filter(id__in=file_ids_to_delete).delete()[0]
    
    logger.info(f"Удалено {deleted_count} старых файлов домашних заданий")
    return f"Удалено {deleted_count} старых файлов"
