"""
Forum Routes
============

Forum topics, replies, and admin moderation.
"""

import logging
from datetime import datetime

from flask import render_template, request, redirect, url_for, flash, jsonify
from flask_login import login_required, current_user

from . import bp
from database import (
    SessionLocal, ForumTopic, ForumReply, ForumAttachment,
    ForumTopicSubscription, ForumReport, ForumEditHistory, User,
    ForumTopicRead, ForumReplyRead
)
from utils.helpers import sanitize_input
from utils.notifications import (
    create_forum_reply_notification,
    create_forum_reaction_notification,
    create_forum_solution_notification,
    create_forum_report_notification,
    parse_mentions_and_notify,
    send_forum_reply_email
)

# Constants
EDIT_TIME_LIMIT_HOURS = 24
AVAILABLE_REACTIONS = ['👍', '❤️']

# Logger
logger = logging.getLogger(__name__)

# Import FileUploadService (may not be available in all environments)
try:
    from file_upload_service import FileUploadService
    FILE_UPLOAD_AVAILABLE = True
except ImportError:
    FILE_UPLOAD_AVAILABLE = False
    logger.warning("FileUploadService not available for forum")


# ============================================================
# PUBLIC FORUM ROUTES
# ============================================================

@bp.route('/forum')
@login_required
def forum_index():
    """Forum - list of topics with category/status/solution filters and search"""
    page = request.args.get('page', 1, type=int)
    per_page = 20
    category_filter = request.args.get('category', '')
    status_filter = request.args.get('status', '')
    has_solution = request.args.get('has_solution', '')
    search_query = request.args.get('q', '').strip()

    db = SessionLocal()
    try:
        # Build query with optional filters (exclude soft-deleted)
        query = db.query(ForumTopic).filter(
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
        )

        if category_filter and category_filter in ForumTopic.CATEGORIES:
            query = query.filter(ForumTopic.category == category_filter)

        if status_filter and status_filter in ForumTopic.STATUSES:
            query = query.filter(ForumTopic.status == status_filter)

        # Filter by has solution
        if has_solution == '1':
            # Topics that have at least one reply marked as solution
            from sqlalchemy import exists
            query = query.filter(
                exists().where(
                    (ForumReply.topic_id == ForumTopic.id) &
                    (ForumReply.is_solution == True)
                )
            )

        # Search in title and content
        if search_query:
            search_term = f'%{search_query}%'
            query = query.filter(
                (ForumTopic.title.ilike(search_term)) |
                (ForumTopic.content.ilike(search_term))
            )

        # Order by pinned first, then by last activity
        query = query.order_by(
            ForumTopic.is_pinned.desc(),
            ForumTopic.updated_at.desc()
        )

        total_topics = query.count()
        topics = query.limit(per_page).offset((page - 1) * per_page).all()

        return render_template(
            'forum/index.html',
            topics=topics,
            page=page,
            per_page=per_page,
            total_topics=total_topics,
            total_pages=(total_topics + per_page - 1) // per_page,
            category_filter=category_filter,
            status_filter=status_filter,
            has_solution=has_solution,
            search_query=search_query,
            categories=ForumTopic.CATEGORIES,
            statuses=ForumTopic.STATUSES,
            category_labels=ForumTopic.CATEGORY_LABELS,
            status_labels=ForumTopic.STATUS_LABELS
        )
    finally:
        db.close()


@bp.route('/forum/nowy', methods=['GET', 'POST'])
@login_required
def forum_new_topic():
    """Create new forum topic with category and attachments"""
    if request.method == 'POST':
        title = sanitize_input(request.form.get('title', ''), 255)
        content = request.form.get('content', '').strip()
        category = request.form.get('category', 'question')

        # Validate category
        if category not in ForumTopic.CATEGORIES:
            category = 'question'

        if not title or len(title) < 5:
            flash('Tytuł musi mieć co najmniej 5 znaków.', 'error')
            return render_template('forum/new_topic.html',
                                   categories=ForumTopic.CATEGORIES,
                                   category_labels=ForumTopic.CATEGORY_LABELS)

        if not content or len(content) < 10:
            flash('Treść musi mieć co najmniej 10 znaków.', 'error')
            return render_template('forum/new_topic.html',
                                   categories=ForumTopic.CATEGORIES,
                                   category_labels=ForumTopic.CATEGORY_LABELS)

        db = SessionLocal()
        try:
            topic = ForumTopic(
                title=title,
                content=content,
                author_id=current_user.id,
                category=category
            )
            db.add(topic)
            db.commit()
            db.refresh(topic)

            # Auto-subscribe author to their own topic
            subscription = ForumTopicSubscription(
                user_id=current_user.id,
                topic_id=topic.id
            )
            db.add(subscription)
            db.commit()

            # Handle file upload
            if FILE_UPLOAD_AVAILABLE and 'attachment' in request.files:
                file = request.files['attachment']
                if file and file.filename:
                    is_valid, error_msg = FileUploadService.validate_file(file)
                    if is_valid:
                        stored_filename, rel_path, file_size, mime_type = FileUploadService.save_file(file, 'topic')
                        attachment = ForumAttachment(
                            attachment_type='topic',
                            topic_id=topic.id,
                            original_filename=file.filename,
                            stored_filename=stored_filename,
                            file_extension=stored_filename.rsplit('.', 1)[-1],
                            file_size=file_size,
                            mime_type=mime_type,
                            uploaded_by=current_user.id
                        )
                        db.add(attachment)
                        db.commit()
                    else:
                        flash(f'Załącznik: {error_msg}', 'warning')

            # Parse @mentions and send notifications
            try:
                author_name = current_user.name or current_user.email.split('@')[0]
                parse_mentions_and_notify(
                    content=content,
                    author_id=current_user.id,
                    author_name=author_name,
                    topic_id=topic.id,
                    content_type='topic',
                    content_id=topic.id
                )
            except Exception as e:
                logger.warning(f"Failed to parse mentions in new topic: {e}")

            flash('Temat został utworzony.', 'success')
            return redirect(url_for('.forum_topic', topic_id=topic.id))
        finally:
            db.close()

    return render_template('forum/new_topic.html',
                           categories=ForumTopic.CATEGORIES,
                           category_labels=ForumTopic.CATEGORY_LABELS)


@bp.route('/forum/<int:topic_id>')
@login_required
def forum_topic(topic_id):
    """View forum topic with replies"""
    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()

        if not topic:
            flash('Temat nie istnieje.', 'error')
            return redirect(url_for('.forum_index'))

        # Check if topic is soft-deleted (only moderators can view)
        if topic.is_deleted and not current_user.can_moderate_forum():
            flash('Temat nie istnieje.', 'error')
            return redirect(url_for('.forum_index'))

        # Increment view count (handle NULL)
        topic.views_count = (topic.views_count or 0) + 1

        # Record topic read by current user
        existing_topic_read = db.query(ForumTopicRead).filter(
            ForumTopicRead.topic_id == topic.id,
            ForumTopicRead.user_id == current_user.id
        ).first()
        if not existing_topic_read:
            db.add(ForumTopicRead(topic_id=topic.id, user_id=current_user.id))

        # Filter soft-deleted replies for non-moderators
        visible_replies = [r for r in topic.replies
                          if not r.is_deleted or current_user.can_moderate_forum()]

        # Record read for all visible replies
        for reply in visible_replies:
            existing_reply_read = db.query(ForumReplyRead).filter(
                ForumReplyRead.reply_id == reply.id,
                ForumReplyRead.user_id == current_user.id
            ).first()
            if not existing_reply_read:
                db.add(ForumReplyRead(reply_id=reply.id, user_id=current_user.id))

        db.commit()

        # Get topic readers
        from sqlalchemy import desc
        topic_readers = db.query(ForumTopicRead).filter(
            ForumTopicRead.topic_id == topic.id
        ).order_by(desc(ForumTopicRead.read_at)).all()

        # Check subscription status
        is_subscribed = db.query(ForumTopicSubscription).filter(
            ForumTopicSubscription.topic_id == topic_id,
            ForumTopicSubscription.user_id == current_user.id
        ).first() is not None

        return render_template('forum/topic.html',
                               topic=topic,
                               visible_replies=visible_replies,
                               topic_readers=topic_readers,
                               is_subscribed=is_subscribed,
                               category_labels=ForumTopic.CATEGORY_LABELS,
                               status_labels=ForumTopic.STATUS_LABELS,
                               available_reactions=AVAILABLE_REACTIONS)
    finally:
        db.close()


@bp.route('/forum/<int:topic_id>/odpowiedz', methods=['POST'])
@login_required
def forum_reply(topic_id):
    """Add reply to forum topic with optional attachment"""
    content = request.form.get('content', '').strip()

    if not content or len(content) < 3:
        flash('Odpowiedź musi mieć co najmniej 3 znaki.', 'error')
        return redirect(url_for('.forum_topic', topic_id=topic_id))

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()

        if not topic:
            flash('Temat nie istnieje.', 'error')
            return redirect(url_for('.forum_index'))

        if topic.is_locked:
            flash('Ten temat jest zamknięty.', 'error')
            return redirect(url_for('.forum_topic', topic_id=topic_id))

        reply = ForumReply(
            topic_id=topic_id,
            author_id=current_user.id,
            content=content
        )
        db.add(reply)
        db.commit()
        db.refresh(reply)

        # Handle multiple file uploads (max 10)
        if FILE_UPLOAD_AVAILABLE:
            MAX_ATTACHMENTS = 10
            files = request.files.getlist('attachments[]')
            if not files:
                # Fallback for single file upload (backward compatibility)
                files = request.files.getlist('attachment')

            uploaded_count = 0
            errors = []

            for file in files[:MAX_ATTACHMENTS]:
                if file and file.filename:
                    is_valid, error_msg = FileUploadService.validate_file(file)
                    if is_valid:
                        stored_filename, rel_path, file_size, mime_type = FileUploadService.save_file(file, 'reply')
                        attachment = ForumAttachment(
                            attachment_type='reply',
                            reply_id=reply.id,
                            original_filename=file.filename,
                            stored_filename=stored_filename,
                            file_extension=stored_filename.rsplit('.', 1)[-1],
                            file_size=file_size,
                            mime_type=mime_type,
                            uploaded_by=current_user.id
                        )
                        db.add(attachment)
                        uploaded_count += 1
                    else:
                        errors.append(f'{file.filename}: {error_msg}')

            if uploaded_count > 0:
                db.commit()

            if errors:
                flash(f'Niektóre załączniki nie zostały dodane: {"; ".join(errors)}', 'warning')

        # Update topic updated_at
        topic.updated_at = datetime.now()
        db.commit()

        # Auto-subscribe replier to topic (if not already subscribed)
        try:
            existing_sub = db.query(ForumTopicSubscription).filter(
                ForumTopicSubscription.topic_id == topic_id,
                ForumTopicSubscription.user_id == current_user.id
            ).first()
            if not existing_sub:
                db.add(ForumTopicSubscription(
                    topic_id=topic_id,
                    user_id=current_user.id,
                    notify_email=True,
                    notify_app=True
                ))
                db.commit()
        except Exception as e:
            logger.warning(f"Failed to auto-subscribe replier: {e}")

        # Send in-app notifications to subscribers (except the replier)
        replier_name = current_user.name or current_user.email.split('@')[0]
        try:
            app_subs = db.query(ForumTopicSubscription).filter(
                ForumTopicSubscription.topic_id == topic_id,
                ForumTopicSubscription.user_id != current_user.id,
                ForumTopicSubscription.notify_app == True
            ).all()

            subscriber_ids = [s.user_id for s in app_subs]
            if subscriber_ids:
                create_forum_reply_notification(
                    topic_id=topic_id,
                    topic_title=topic.title,
                    replier_name=replier_name,
                    reply_id=reply.id,
                    subscriber_ids=subscriber_ids
                )
        except Exception as e:
            logger.warning(f"Failed to send reply notifications: {e}")

        # Send email notifications to subscribers with notify_email=True
        try:
            email_subs = db.query(ForumTopicSubscription).filter(
                ForumTopicSubscription.topic_id == topic_id,
                ForumTopicSubscription.user_id != current_user.id,
                ForumTopicSubscription.notify_email == True
            ).all()

            if email_subs:
                subscriber_emails = []
                for sub in email_subs:
                    user = db.query(User).filter(User.id == sub.user_id).first()
                    if user and user.email:
                        subscriber_emails.append({
                            'email': user.email,
                            'name': user.name or user.email.split('@')[0]
                        })

                if subscriber_emails:
                    send_forum_reply_email(
                        topic_id=topic_id,
                        topic_title=topic.title,
                        replier_name=replier_name,
                        reply_content=content,
                        subscriber_emails=subscriber_emails
                    )
        except Exception as e:
            logger.warning(f"Failed to send email notifications: {e}")

        # Parse @mentions and send notifications
        try:
            author_name = current_user.name or current_user.email.split('@')[0]
            parse_mentions_and_notify(
                content=content,
                author_id=current_user.id,
                author_name=author_name,
                topic_id=topic_id,
                content_type='reply',
                content_id=reply.id
            )
        except Exception as e:
            logger.warning(f"Failed to parse mentions: {e}")

        flash('Odpowiedź dodana.', 'success')
        return redirect(url_for('.forum_topic', topic_id=topic_id))
    finally:
        db.close()


# ============================================================
# ADMIN FORUM ROUTES
# ============================================================

@bp.route('/admin/forum')
@login_required
def admin_forum():
    """Admin panel for forum moderation"""
    if not current_user.can_moderate_forum():
        flash('Brak uprawnień do tej strony.', 'error')
        return redirect(url_for('.forum_index'))

    db = SessionLocal()
    try:
        # Get all topics with stats
        topics = db.query(ForumTopic).order_by(
            ForumTopic.created_at.desc()
        ).all()

        # Get recent replies
        recent_replies = db.query(ForumReply).order_by(
            ForumReply.created_at.desc()
        ).limit(50).all()

        # Stats
        total_topics = len(topics)
        total_replies = db.query(ForumReply).count()
        pinned_count = sum(1 for t in topics if t.is_pinned)
        locked_count = sum(1 for t in topics if t.is_locked)

        # Category and status stats
        category_counts = {}
        status_counts = {}
        for t in topics:
            cat = t.category or 'question'
            status = t.status or 'new'
            category_counts[cat] = category_counts.get(cat, 0) + 1
            status_counts[status] = status_counts.get(status, 0) + 1

        return render_template(
            'admin/forum.html',
            topics=topics,
            recent_replies=recent_replies,
            total_topics=total_topics,
            total_replies=total_replies,
            pinned_count=pinned_count,
            locked_count=locked_count,
            category_counts=category_counts,
            status_counts=status_counts,
            categories=ForumTopic.CATEGORIES,
            statuses=ForumTopic.STATUSES,
            category_labels=ForumTopic.CATEGORY_LABELS,
            status_labels=ForumTopic.STATUS_LABELS
        )
    finally:
        db.close()


@bp.route('/admin/forum/topic/<int:topic_id>/pin', methods=['POST'])
@login_required
def admin_forum_pin(topic_id):
    """Toggle topic pin status"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        topic.is_pinned = not topic.is_pinned
        db.commit()

        logger.info(f"Admin {current_user.email} {'pinned' if topic.is_pinned else 'unpinned'} topic #{topic_id}")
        return jsonify({
            'success': True,
            'is_pinned': topic.is_pinned,
            'message': f"Temat {'przypięty' if topic.is_pinned else 'odpięty'}"
        })
    finally:
        db.close()


@bp.route('/admin/forum/topic/<int:topic_id>/lock', methods=['POST'])
@login_required
def admin_forum_lock(topic_id):
    """Toggle topic lock status"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        topic.is_locked = not topic.is_locked
        db.commit()

        logger.info(f"Admin {current_user.email} {'locked' if topic.is_locked else 'unlocked'} topic #{topic_id}")
        return jsonify({
            'success': True,
            'is_locked': topic.is_locked,
            'message': f"Temat {'zamknięty' if topic.is_locked else 'otwarty'}"
        })
    finally:
        db.close()


@bp.route('/admin/forum/topic/<int:topic_id>/delete', methods=['POST'])
@login_required
def admin_forum_delete_topic(topic_id):
    """Delete topic and all its replies"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        topic_title = topic.title
        db.delete(topic)  # Cascade deletes replies
        db.commit()

        logger.info(f"Admin {current_user.email} deleted topic #{topic_id}: {topic_title}")
        return jsonify({
            'success': True,
            'message': 'Temat usunięty'
        })
    finally:
        db.close()


@bp.route('/admin/forum/reply/<int:reply_id>/delete', methods=['POST'])
@login_required
def admin_forum_delete_reply(reply_id):
    """Delete a reply"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        reply = db.query(ForumReply).filter(ForumReply.id == reply_id).first()
        if not reply:
            return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        topic_id = reply.topic_id
        # Delete dependent records first (reply reads, attachments, reports, edit history)
        db.query(ForumReplyRead).filter(ForumReplyRead.reply_id == reply_id).delete()
        db.query(ForumAttachment).filter(ForumAttachment.reply_id == reply_id).delete()
        db.query(ForumReport).filter(ForumReport.reply_id == reply_id).delete()
        db.query(ForumEditHistory).filter(ForumEditHistory.reply_id == reply_id).delete()
        db.delete(reply)
        db.commit()

        logger.info(f"Admin {current_user.email} deleted reply #{reply_id} from topic #{topic_id}")
        return jsonify({
            'success': True,
            'message': 'Odpowiedź usunięta'
        })
    finally:
        db.close()


@bp.route('/admin/forum/topic/<int:topic_id>/status', methods=['POST'])
@login_required
def admin_forum_change_status(topic_id):
    """Change topic status (moderators only)"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    data = request.get_json() or {}
    new_status = data.get('status')
    note = data.get('note', '').strip()

    if not new_status or new_status not in ForumTopic.STATUSES:
        return jsonify({'success': False, 'error': 'Nieprawidłowy status'}), 400

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        old_status = topic.status
        topic.status = new_status
        topic.status_changed_by = current_user.id
        topic.status_changed_at = datetime.now()
        if note:
            topic.status_note = note
        db.commit()

        logger.info(f"Admin {current_user.email} changed topic #{topic_id} status: {old_status} -> {new_status}")
        return jsonify({
            'success': True,
            'status': new_status,
            'status_label': ForumTopic.STATUS_LABELS.get(new_status, new_status),
            'message': f"Status zmieniony na: {ForumTopic.STATUS_LABELS.get(new_status, new_status)}"
        })
    finally:
        db.close()


@bp.route('/admin/forum/bulk-action', methods=['POST'])
@login_required
def admin_forum_bulk_action():
    """Perform bulk action on multiple topics (moderators only)"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    data = request.get_json() or {}
    topic_ids = data.get('topic_ids', [])
    action = data.get('action')

    if not topic_ids or not isinstance(topic_ids, list):
        return jsonify({'success': False, 'error': 'Nie wybrano tematów'}), 400

    if action not in ['pin', 'unpin', 'lock', 'unlock', 'status', 'delete']:
        return jsonify({'success': False, 'error': 'Nieprawidłowa akcja'}), 400

    db = SessionLocal()
    try:
        topics = db.query(ForumTopic).filter(ForumTopic.id.in_(topic_ids)).all()

        if not topics:
            return jsonify({'success': False, 'error': 'Nie znaleziono tematów'}), 404

        count = len(topics)

        if action == 'pin':
            for topic in topics:
                topic.is_pinned = True
            message = f'Przypięto {count} tematów'

        elif action == 'unpin':
            for topic in topics:
                topic.is_pinned = False
            message = f'Odpięto {count} tematów'

        elif action == 'lock':
            for topic in topics:
                topic.is_locked = True
            message = f'Zablokowano {count} tematów'

        elif action == 'unlock':
            for topic in topics:
                topic.is_locked = False
            message = f'Odblokowano {count} tematów'

        elif action == 'status':
            new_status = data.get('status')
            if not new_status or new_status not in ForumTopic.STATUSES:
                return jsonify({'success': False, 'error': 'Nieprawidłowy status'}), 400
            for topic in topics:
                topic.status = new_status
                topic.status_changed_by = current_user.id
                topic.status_changed_at = datetime.now()
            status_label = ForumTopic.STATUS_LABELS.get(new_status, new_status)
            message = f'Zmieniono status {count} tematów na: {status_label}'

        elif action == 'delete':
            # Soft delete topics
            for topic in topics:
                topic.is_deleted = True
                topic.deleted_at = datetime.now()
                topic.deleted_by = current_user.id
            message = f'Usunięto {count} tematów'

        db.commit()
        logger.info(f"Admin {current_user.email} performed bulk action '{action}' on {count} topics: {topic_ids}")

        return jsonify({
            'success': True,
            'message': message,
            'affected_count': count
        })

    except Exception as e:
        db.rollback()
        logger.error(f"Error in bulk action: {e}")
        return jsonify({'success': False, 'error': 'Wystąpił błąd'}), 500
    finally:
        db.close()


# ============================================================
# USER FORUM ACTIONS (edit, delete, reactions, subscriptions)
# ============================================================

def _can_edit_content(content_created_at):
    """Check if content is within editable time window (24h)"""
    if not content_created_at:
        return False
    from datetime import timedelta
    return datetime.now() - content_created_at < timedelta(hours=EDIT_TIME_LIMIT_HOURS)


@bp.route('/forum/topic/<int:topic_id>/edit', methods=['POST'])
@login_required
def edit_topic(topic_id):
    """Edit own topic (within 24h)"""
    data = request.get_json() or {}
    new_content = data.get('content', '').strip()

    if not new_content or len(new_content) < 10:
        return jsonify({'success': False, 'error': 'Treść musi mieć co najmniej 10 znaków'}), 400

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        # Check ownership (unless moderator)
        if topic.author_id != current_user.id and not current_user.can_moderate_forum():
            return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

        # Check time limit (unless moderator)
        if not current_user.can_moderate_forum() and not _can_edit_content(topic.created_at):
            return jsonify({'success': False, 'error': 'Minął limit czasu edycji (24h)'}), 403

        if topic.is_locked:
            return jsonify({'success': False, 'error': 'Temat jest zamknięty'}), 403

        # Save edit history
        history = ForumEditHistory(
            content_type='topic',
            topic_id=topic.id,
            editor_id=current_user.id,
            old_content=topic.content,
            new_content=new_content,
            edit_reason=data.get('reason', '')
        )
        db.add(history)

        # Update topic
        topic.content = new_content
        topic.edited_at = datetime.now()
        topic.edited_by = current_user.id
        topic.edit_count = (topic.edit_count or 0) + 1
        db.commit()

        logger.info(f"User {current_user.email} edited topic #{topic_id}")
        return jsonify({
            'success': True,
            'message': 'Temat zaktualizowany',
            'edit_count': topic.edit_count,
            'edited_at': topic.edited_at.isoformat()
        })
    finally:
        db.close()


@bp.route('/forum/reply/<int:reply_id>/edit', methods=['POST'])
@login_required
def edit_reply(reply_id):
    """Edit own reply (within 24h)"""
    data = request.get_json() or {}
    new_content = data.get('content', '').strip()

    if not new_content or len(new_content) < 3:
        return jsonify({'success': False, 'error': 'Treść musi mieć co najmniej 3 znaki'}), 400

    db = SessionLocal()
    try:
        reply = db.query(ForumReply).filter(ForumReply.id == reply_id).first()
        if not reply:
            return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        # Check ownership (unless moderator)
        if reply.author_id != current_user.id and not current_user.can_moderate_forum():
            return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

        # Check time limit (unless moderator)
        if not current_user.can_moderate_forum() and not _can_edit_content(reply.created_at):
            return jsonify({'success': False, 'error': 'Minął limit czasu edycji (24h)'}), 403

        # Check if topic is locked
        topic = db.query(ForumTopic).filter(ForumTopic.id == reply.topic_id).first()
        if topic and topic.is_locked:
            return jsonify({'success': False, 'error': 'Temat jest zamknięty'}), 403

        # Save edit history
        history = ForumEditHistory(
            content_type='reply',
            reply_id=reply.id,
            editor_id=current_user.id,
            old_content=reply.content,
            new_content=new_content,
            edit_reason=data.get('reason', '')
        )
        db.add(history)

        # Update reply
        reply.content = new_content
        reply.edited_at = datetime.now()
        reply.edited_by = current_user.id
        reply.edit_count = (reply.edit_count or 0) + 1
        db.commit()

        logger.info(f"User {current_user.email} edited reply #{reply_id}")
        return jsonify({
            'success': True,
            'message': 'Odpowiedź zaktualizowana',
            'edit_count': reply.edit_count,
            'edited_at': reply.edited_at.isoformat()
        })
    finally:
        db.close()


@bp.route('/forum/reply/<int:reply_id>/delete', methods=['POST'])
@login_required
def delete_own_reply(reply_id):
    """Soft delete own reply (if no child responses exist)"""
    db = SessionLocal()
    try:
        reply = db.query(ForumReply).filter(ForumReply.id == reply_id).first()
        if not reply:
            return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        # Check ownership
        if reply.author_id != current_user.id and not current_user.can_moderate_forum():
            return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

        # Check if topic is locked
        topic = db.query(ForumTopic).filter(ForumTopic.id == reply.topic_id).first()
        if topic and topic.is_locked:
            return jsonify({'success': False, 'error': 'Temat jest zamknięty'}), 403

        # Soft delete
        reply.is_deleted = True
        reply.deleted_at = datetime.now()
        reply.deleted_by = current_user.id
        db.commit()

        logger.info(f"User {current_user.email} soft-deleted reply #{reply_id}")
        return jsonify({
            'success': True,
            'message': 'Odpowiedź usunięta'
        })
    finally:
        db.close()


@bp.route('/forum/topic/<int:topic_id>/react', methods=['POST'])
@login_required
def react_to_topic(topic_id):
    """Add or remove reaction from topic"""
    data = request.get_json() or {}
    reaction = data.get('reaction')

    if reaction not in AVAILABLE_REACTIONS:
        return jsonify({'success': False, 'error': 'Nieprawidłowa reakcja'}), 400

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        # Get current reactions (handle None)
        reactions = topic.reactions or {}
        if not isinstance(reactions, dict):
            reactions = {}

        # Toggle reaction
        user_id = current_user.id
        if reaction not in reactions:
            reactions[reaction] = []

        if user_id in reactions[reaction]:
            reactions[reaction].remove(user_id)
            action = 'removed'
        else:
            # Remove user from other reactions first (one reaction per user)
            for r in AVAILABLE_REACTIONS:
                if r in reactions and user_id in reactions[r]:
                    reactions[r].remove(user_id)
            reactions[reaction].append(user_id)
            action = 'added'

        # Clean up empty reaction lists
        reactions = {k: v for k, v in reactions.items() if v}

        topic.reactions = reactions
        db.commit()

        return jsonify({
            'success': True,
            'action': action,
            'reactions': {k: len(v) for k, v in reactions.items()},
            'user_reaction': reaction if action == 'added' else None
        })
    finally:
        db.close()


@bp.route('/forum/reply/<int:reply_id>/react', methods=['POST'])
@login_required
def react_to_reply(reply_id):
    """Add or remove reaction from reply"""
    data = request.get_json() or {}
    reaction = data.get('reaction')

    if reaction not in AVAILABLE_REACTIONS:
        return jsonify({'success': False, 'error': 'Nieprawidłowa reakcja'}), 400

    db = SessionLocal()
    try:
        reply = db.query(ForumReply).filter(ForumReply.id == reply_id).first()
        if not reply:
            return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        # Get current reactions (handle None)
        reactions = reply.reactions or {}
        if not isinstance(reactions, dict):
            reactions = {}

        # Toggle reaction
        user_id = current_user.id
        if reaction not in reactions:
            reactions[reaction] = []

        if user_id in reactions[reaction]:
            reactions[reaction].remove(user_id)
            action = 'removed'
        else:
            # Remove user from other reactions first
            for r in AVAILABLE_REACTIONS:
                if r in reactions and user_id in reactions[r]:
                    reactions[r].remove(user_id)
            reactions[reaction].append(user_id)
            action = 'added'

        # Clean up empty reaction lists
        reactions = {k: v for k, v in reactions.items() if v}

        reply.reactions = reactions
        db.commit()

        # Send notification to reply author (if adding reaction and not own content)
        if action == 'added' and reply.author_id != current_user.id:
            try:
                reactor_name = current_user.name or current_user.email.split('@')[0]
                create_forum_reaction_notification(
                    user_id=reply.author_id,
                    reactor_name=reactor_name,
                    content_type='reply',
                    content_id=reply.id,
                    topic_id=reply.topic_id,
                    emoji=reaction
                )
            except Exception as e:
                logger.warning(f"Failed to send reaction notification: {e}")

        return jsonify({
            'success': True,
            'action': action,
            'reactions': {k: len(v) for k, v in reactions.items()},
            'user_reaction': reaction if action == 'added' else None
        })
    finally:
        db.close()


@bp.route('/forum/topic/<int:topic_id>/subscribe', methods=['POST'])
@login_required
def subscribe_to_topic(topic_id):
    """Subscribe to topic notifications"""
    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        # Check if already subscribed
        existing = db.query(ForumTopicSubscription).filter(
            ForumTopicSubscription.topic_id == topic_id,
            ForumTopicSubscription.user_id == current_user.id
        ).first()

        if existing:
            return jsonify({'success': False, 'error': 'Już obserwujesz ten temat'}), 400

        subscription = ForumTopicSubscription(
            user_id=current_user.id,
            topic_id=topic_id
        )
        db.add(subscription)
        db.commit()

        logger.info(f"User {current_user.email} subscribed to topic #{topic_id}")
        return jsonify({
            'success': True,
            'message': 'Zasubskrybowano temat'
        })
    finally:
        db.close()


@bp.route('/forum/topic/<int:topic_id>/unsubscribe', methods=['POST'])
@login_required
def unsubscribe_from_topic(topic_id):
    """Unsubscribe from topic notifications"""
    db = SessionLocal()
    try:
        subscription = db.query(ForumTopicSubscription).filter(
            ForumTopicSubscription.topic_id == topic_id,
            ForumTopicSubscription.user_id == current_user.id
        ).first()

        if not subscription:
            return jsonify({'success': False, 'error': 'Nie obserwujesz tego tematu'}), 400

        db.delete(subscription)
        db.commit()

        logger.info(f"User {current_user.email} unsubscribed from topic #{topic_id}")
        return jsonify({
            'success': True,
            'message': 'Anulowano subskrypcję'
        })
    finally:
        db.close()


@bp.route('/forum/<int:topic_id>/unsubscribe', methods=['GET'])
@login_required
def unsubscribe_from_email(topic_id):
    """Unsubscribe from topic via email link (GET, requires login)"""
    db = SessionLocal()
    try:
        subscription = db.query(ForumTopicSubscription).filter(
            ForumTopicSubscription.topic_id == topic_id,
            ForumTopicSubscription.user_id == current_user.id
        ).first()

        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        topic_title = topic.title if topic else f"#{topic_id}"

        if subscription:
            db.delete(subscription)
            db.commit()
            flash(f'Przestales obserwowac watek: {topic_title}', 'success')
        else:
            flash('Nie obserwujesz tego watku.', 'info')

        return redirect(url_for('.forum_topic', topic_id=topic_id))
    finally:
        db.close()


@bp.route('/forum/report', methods=['POST'])
@login_required
def report_content():
    """Report topic or reply for moderation"""
    data = request.get_json() or {}
    content_type = data.get('content_type')
    content_id = data.get('content_id')
    reason = data.get('reason')
    description = data.get('description', '').strip()

    if content_type not in ['topic', 'reply']:
        return jsonify({'success': False, 'error': 'Nieprawidłowy typ treści'}), 400

    if reason not in ForumReport.REASONS:
        return jsonify({'success': False, 'error': 'Nieprawidłowy powód'}), 400

    db = SessionLocal()
    try:
        # Verify content exists
        if content_type == 'topic':
            content = db.query(ForumTopic).filter(ForumTopic.id == content_id).first()
            if not content:
                return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404
        else:
            content = db.query(ForumReply).filter(ForumReply.id == content_id).first()
            if not content:
                return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        # Check if user already reported this content
        existing = db.query(ForumReport).filter(
            ForumReport.reporter_id == current_user.id,
            ForumReport.content_type == content_type,
            (ForumReport.topic_id == content_id if content_type == 'topic' else ForumReport.reply_id == content_id)
        ).first()

        if existing:
            return jsonify({'success': False, 'error': 'Już zgłosiłeś tę treść'}), 400

        report = ForumReport(
            reporter_id=current_user.id,
            content_type=content_type,
            topic_id=content_id if content_type == 'topic' else None,
            reply_id=content_id if content_type == 'reply' else None,
            reason=reason,
            description=description
        )
        db.add(report)
        db.commit()
        db.refresh(report)

        # Notify admins about the report
        try:
            admin_users = db.query(User).filter(User.role == 'ADMIN', User.is_active == True).all()
            admin_ids = [u.id for u in admin_users]
            reporter_name = current_user.name or current_user.email.split('@')[0]
            create_forum_report_notification(
                admin_user_ids=admin_ids,
                report_id=report.id,
                content_type=content_type,
                reporter_name=reporter_name
            )
        except Exception as e:
            logger.warning(f"Failed to send report notification: {e}")

        logger.info(f"User {current_user.email} reported {content_type} #{content_id}: {reason}")
        return jsonify({
            'success': True,
            'message': 'Zgłoszenie zostało wysłane'
        })
    finally:
        db.close()


# ============================================================
# EXTENDED ADMIN ROUTES (edit, restore, reports, history)
# ============================================================

@bp.route('/admin/forum/topic/<int:topic_id>/admin-edit', methods=['POST'])
@login_required
def admin_edit_topic(topic_id):
    """Moderator: Edit any topic content"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    data = request.get_json() or {}
    new_content = data.get('content', '').strip()
    new_title = data.get('title', '').strip()

    if not new_content or len(new_content) < 10:
        return jsonify({'success': False, 'error': 'Treść musi mieć co najmniej 10 znaków'}), 400

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        # Save edit history
        old_content = topic.content
        if new_title:
            old_content = f"[Title: {topic.title}]\n{old_content}"
            new_content_with_title = f"[Title: {new_title}]\n{new_content}"
        else:
            new_content_with_title = new_content

        history = ForumEditHistory(
            content_type='topic',
            topic_id=topic.id,
            editor_id=current_user.id,
            old_content=old_content,
            new_content=new_content_with_title,
            edit_reason=data.get('reason', 'Edycja admina')
        )
        db.add(history)

        # Update topic
        if new_title:
            topic.title = new_title
        topic.content = new_content
        topic.edited_at = datetime.now()
        topic.edited_by = current_user.id
        topic.edit_count = (topic.edit_count or 0) + 1
        db.commit()

        logger.info(f"Admin {current_user.email} edited topic #{topic_id}")
        return jsonify({
            'success': True,
            'message': 'Temat zaktualizowany przez admina'
        })
    finally:
        db.close()


@bp.route('/admin/forum/reply/<int:reply_id>/admin-edit', methods=['POST'])
@login_required
def admin_edit_reply(reply_id):
    """Moderator: Edit any reply content"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    data = request.get_json() or {}
    new_content = data.get('content', '').strip()

    if not new_content or len(new_content) < 3:
        return jsonify({'success': False, 'error': 'Treść musi mieć co najmniej 3 znaki'}), 400

    db = SessionLocal()
    try:
        reply = db.query(ForumReply).filter(ForumReply.id == reply_id).first()
        if not reply:
            return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        # Save edit history
        history = ForumEditHistory(
            content_type='reply',
            reply_id=reply.id,
            editor_id=current_user.id,
            old_content=reply.content,
            new_content=new_content,
            edit_reason=data.get('reason', 'Edycja admina')
        )
        db.add(history)

        # Update reply
        reply.content = new_content
        reply.edited_at = datetime.now()
        reply.edited_by = current_user.id
        reply.edit_count = (reply.edit_count or 0) + 1
        db.commit()

        logger.info(f"Admin {current_user.email} edited reply #{reply_id}")
        return jsonify({
            'success': True,
            'message': 'Odpowiedź zaktualizowana przez admina'
        })
    finally:
        db.close()


@bp.route('/admin/forum/reply/<int:reply_id>/solution', methods=['POST'])
@login_required
def mark_as_solution(reply_id):
    """Moderator: Mark reply as solution"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        reply = db.query(ForumReply).filter(ForumReply.id == reply_id).first()
        if not reply:
            return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        # Toggle solution status
        if reply.is_solution:
            reply.is_solution = False
            reply.marked_as_solution_by = None
            reply.marked_as_solution_at = None
            message = 'Usunięto oznaczenie rozwiązania'
        else:
            # Remove solution from other replies in the same topic
            db.query(ForumReply).filter(
                ForumReply.topic_id == reply.topic_id,
                ForumReply.is_solution == True
            ).update({'is_solution': False, 'marked_as_solution_by': None, 'marked_as_solution_at': None})

            reply.is_solution = True
            reply.marked_as_solution_by = current_user.id
            reply.marked_as_solution_at = datetime.now()
            message = 'Oznaczono jako rozwiązanie'

            # Notify topic author
            topic = db.query(ForumTopic).filter(ForumTopic.id == reply.topic_id).first()
            if topic and topic.author_id != reply.author_id:
                try:
                    create_forum_solution_notification(
                        user_id=topic.author_id,
                        topic_id=topic.id,
                        topic_title=topic.title
                    )
                except Exception as e:
                    logger.warning(f"Failed to send solution notification: {e}")

        db.commit()

        logger.info(f"Admin {current_user.email} {'marked' if reply.is_solution else 'unmarked'} reply #{reply_id} as solution")
        return jsonify({
            'success': True,
            'is_solution': reply.is_solution,
            'message': message
        })
    finally:
        db.close()


@bp.route('/admin/forum/topic/<int:topic_id>/restore', methods=['POST'])
@login_required
def restore_topic(topic_id):
    """Moderator: Restore soft-deleted topic"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        if not topic.is_deleted:
            return jsonify({'success': False, 'error': 'Temat nie jest usunięty'}), 400

        topic.is_deleted = False
        topic.deleted_at = None
        topic.deleted_by = None
        db.commit()

        logger.info(f"Admin {current_user.email} restored topic #{topic_id}")
        return jsonify({
            'success': True,
            'message': 'Temat przywrócony'
        })
    finally:
        db.close()


@bp.route('/admin/forum/reply/<int:reply_id>/restore', methods=['POST'])
@login_required
def restore_reply(reply_id):
    """Moderator: Restore soft-deleted reply"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        reply = db.query(ForumReply).filter(ForumReply.id == reply_id).first()
        if not reply:
            return jsonify({'success': False, 'error': 'Odpowiedź nie istnieje'}), 404

        if not reply.is_deleted:
            return jsonify({'success': False, 'error': 'Odpowiedź nie jest usunięta'}), 400

        reply.is_deleted = False
        reply.deleted_at = None
        reply.deleted_by = None
        db.commit()

        logger.info(f"Admin {current_user.email} restored reply #{reply_id}")
        return jsonify({
            'success': True,
            'message': 'Odpowiedź przywrócona'
        })
    finally:
        db.close()


@bp.route('/admin/forum/reports')
@login_required
def admin_forum_reports():
    """Moderator: View all reports"""
    if not current_user.can_moderate_forum():
        flash('Brak uprawnień do tej strony.', 'error')
        return redirect(url_for('.forum_index'))

    status_filter = request.args.get('status', 'pending')

    db = SessionLocal()
    try:
        query = db.query(ForumReport).order_by(ForumReport.created_at.desc())

        if status_filter in ['pending', 'reviewed', 'dismissed']:
            query = query.filter(ForumReport.status == status_filter)

        reports = query.all()

        # Get stats
        pending_count = db.query(ForumReport).filter(ForumReport.status == 'pending').count()
        reviewed_count = db.query(ForumReport).filter(ForumReport.status == 'reviewed').count()
        dismissed_count = db.query(ForumReport).filter(ForumReport.status == 'dismissed').count()

        return render_template(
            'admin/forum_reports.html',
            reports=reports,
            status_filter=status_filter,
            pending_count=pending_count,
            reviewed_count=reviewed_count,
            dismissed_count=dismissed_count,
            reason_labels=ForumReport.REASON_LABELS
        )
    finally:
        db.close()


@bp.route('/admin/forum/report/<int:report_id>/review', methods=['POST'])
@login_required
def review_report(report_id):
    """Moderator: Review a report"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    data = request.get_json() or {}
    new_status = data.get('status')
    review_note = data.get('note', '').strip()

    if new_status not in ['reviewed', 'dismissed']:
        return jsonify({'success': False, 'error': 'Nieprawidłowy status'}), 400

    db = SessionLocal()
    try:
        report = db.query(ForumReport).filter(ForumReport.id == report_id).first()
        if not report:
            return jsonify({'success': False, 'error': 'Zgłoszenie nie istnieje'}), 404

        report.status = new_status
        report.reviewed_by = current_user.id
        report.reviewed_at = datetime.now()
        report.review_note = review_note
        db.commit()

        logger.info(f"Admin {current_user.email} reviewed report #{report_id}: {new_status}")
        return jsonify({
            'success': True,
            'message': f"Zgłoszenie {'rozpatrzone' if new_status == 'reviewed' else 'odrzucone'}"
        })
    finally:
        db.close()


@bp.route('/admin/forum/topic/<int:topic_id>/history')
@login_required
def topic_edit_history(topic_id):
    """Moderator: View topic edit history"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        history = db.query(ForumEditHistory).filter(
            ForumEditHistory.content_type == 'topic',
            ForumEditHistory.topic_id == topic_id
        ).order_by(ForumEditHistory.created_at.desc()).all()

        return jsonify({
            'success': True,
            'history': [{
                'id': h.id,
                'editor': h.editor.full_name if h.editor else 'Nieznany',
                'old_content': h.old_content[:200] + '...' if len(h.old_content) > 200 else h.old_content,
                'new_content': h.new_content[:200] + '...' if len(h.new_content) > 200 else h.new_content,
                'edit_reason': h.edit_reason,
                'created_at': h.created_at.isoformat()
            } for h in history]
        })
    finally:
        db.close()


@bp.route('/admin/forum/reply/<int:reply_id>/history')
@login_required
def reply_edit_history(reply_id):
    """Moderator: View reply edit history"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnień'}), 403

    db = SessionLocal()
    try:
        history = db.query(ForumEditHistory).filter(
            ForumEditHistory.content_type == 'reply',
            ForumEditHistory.reply_id == reply_id
        ).order_by(ForumEditHistory.created_at.desc()).all()

        return jsonify({
            'success': True,
            'history': [{
                'id': h.id,
                'editor': h.editor.full_name if h.editor else 'Nieznany',
                'old_content': h.old_content[:200] + '...' if len(h.old_content) > 200 else h.old_content,
                'new_content': h.new_content[:200] + '...' if len(h.new_content) > 200 else h.new_content,
                'edit_reason': h.edit_reason,
                'created_at': h.created_at.isoformat()
            } for h in history]
        })
    finally:
        db.close()


@bp.route('/admin/forum/deleted')
@login_required
def admin_deleted_content():
    """Moderator: View soft-deleted topics and replies"""
    if not current_user.can_moderate_forum():
        flash('Brak uprawnień do tej strony.', 'error')
        return redirect(url_for('.forum_index'))

    db = SessionLocal()
    try:
        deleted_topics = db.query(ForumTopic).filter(
            ForumTopic.is_deleted == True
        ).order_by(ForumTopic.deleted_at.desc()).all()

        deleted_replies = db.query(ForumReply).filter(
            ForumReply.is_deleted == True
        ).order_by(ForumReply.deleted_at.desc()).all()

        return render_template(
            'admin/forum_deleted.html',
            deleted_topics=deleted_topics,
            deleted_replies=deleted_replies
        )
    finally:
        db.close()


# ============================================================
# USER STATISTICS
# ============================================================

@bp.route('/forum/user/<int:user_id>/stats')
@login_required
def user_forum_stats(user_id):
    """Get forum statistics for a user (for tooltip display)"""
    from sqlalchemy import func

    db = SessionLocal()
    try:
        # Count topics created
        topic_count = db.query(func.count(ForumTopic.id)).filter(
            ForumTopic.author_id == user_id,
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
        ).scalar() or 0

        # Count replies created
        reply_count = db.query(func.count(ForumReply.id)).filter(
            ForumReply.author_id == user_id,
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).scalar() or 0

        # Count solutions marked
        solution_count = db.query(func.count(ForumReply.id)).filter(
            ForumReply.author_id == user_id,
            ForumReply.is_solution == True,
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).scalar() or 0

        # Count reactions received on user's topics and replies
        # Using JSONB - count non-empty reaction arrays
        reactions_received = 0

        # Get user's topics with reactions
        user_topics = db.query(ForumTopic).filter(
            ForumTopic.author_id == user_id,
            ForumTopic.reactions.isnot(None)
        ).all()
        for topic in user_topics:
            if topic.reactions:
                for emoji, user_ids in topic.reactions.items():
                    if isinstance(user_ids, list):
                        reactions_received += len(user_ids)

        # Get user's replies with reactions
        user_replies = db.query(ForumReply).filter(
            ForumReply.author_id == user_id,
            ForumReply.reactions.isnot(None)
        ).all()
        for reply in user_replies:
            if reply.reactions:
                for emoji, user_ids in reply.reactions.items():
                    if isinstance(user_ids, list):
                        reactions_received += len(user_ids)

        # Get user info
        user = db.query(User).filter(User.id == user_id).first()
        user_name = user.full_name if user else 'Nieznany'

        return jsonify({
            'success': True,
            'user_id': user_id,
            'user_name': user_name,
            'stats': {
                'topics': topic_count,
                'replies': reply_count,
                'solutions': solution_count,
                'reactions_received': reactions_received,
                'total_posts': topic_count + reply_count
            }
        })
    except Exception as e:
        logger.error(f"Error getting user stats: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500
    finally:
        db.close()


# ============================================================
# ADMIN ANALYTICS & TOOLS
# ============================================================

@bp.route('/admin/forum/analytics')
@login_required
def admin_forum_analytics():
    """Forum analytics dashboard with stats, charts, and rankings"""
    if not current_user.can_moderate_forum():
        flash('Brak uprawnien do tej strony.', 'error')
        return redirect(url_for('.forum_index'))

    from sqlalchemy import func, distinct
    from datetime import timedelta

    # Date range from query params (default: last 30 days)
    end_date_str = request.args.get('end_date', datetime.now().strftime('%Y-%m-%d'))
    start_date_str = request.args.get('start_date', (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'))

    try:
        end_date = datetime.strptime(end_date_str, '%Y-%m-%d')
        start_date = datetime.strptime(start_date_str, '%Y-%m-%d')
    except ValueError:
        end_date = datetime.now()
        start_date = end_date - timedelta(days=30)

    # Ensure end_date is end of day
    end_date = end_date.replace(hour=23, minute=59, second=59)

    db = SessionLocal()
    try:
        # Basic stats
        total_topics = db.query(func.count(ForumTopic.id)).filter(
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
        ).scalar() or 0

        total_replies = db.query(func.count(ForumReply.id)).filter(
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).scalar() or 0

        # This month stats
        month_start = datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        topics_this_month = db.query(func.count(ForumTopic.id)).filter(
            ForumTopic.created_at >= month_start,
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
        ).scalar() or 0

        replies_this_month = db.query(func.count(ForumReply.id)).filter(
            ForumReply.created_at >= month_start,
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).scalar() or 0

        # Active users in last 7 days
        week_ago = datetime.now() - timedelta(days=7)
        active_topic_authors = db.query(distinct(ForumTopic.author_id)).filter(
            ForumTopic.created_at >= week_ago
        ).count()
        active_reply_authors = db.query(distinct(ForumReply.author_id)).filter(
            ForumReply.created_at >= week_ago
        ).count()
        # Unique active users (simplified - just sum for now)
        active_users_7d = max(active_topic_authors, active_reply_authors)

        # Unanswered topics count
        unanswered_count = db.query(func.count(ForumTopic.id)).filter(
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None)),
            ~ForumTopic.id.in_(
                db.query(distinct(ForumReply.topic_id)).filter(
                    (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
                )
            )
        ).scalar() or 0

        # Resolved topics
        resolved_count = db.query(func.count(ForumTopic.id)).filter(
            ForumTopic.status == 'resolved',
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
        ).scalar() or 0

        # Average response time (simplified - in hours)
        # For now, just show "< 24h" as placeholder
        avg_response_time = "< 24h"

        stats = {
            'total_topics': total_topics,
            'total_replies': total_replies,
            'topics_this_month': topics_this_month,
            'replies_this_month': replies_this_month,
            'active_users_7d': active_users_7d,
            'unanswered_topics': unanswered_count,
            'resolved_topics': resolved_count,
            'avg_response_time': avg_response_time
        }

        # Unanswered topics list
        replied_topic_ids = db.query(distinct(ForumReply.topic_id)).filter(
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).subquery()

        unanswered_topics = db.query(ForumTopic).filter(
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None)),
            ~ForumTopic.id.in_(replied_topic_ids)
        ).order_by(ForumTopic.created_at.asc()).limit(20).all()

        # Add days_waiting attribute
        now = datetime.now()
        for topic in unanswered_topics:
            topic.days_waiting = (now - topic.created_at).days

        # User rankings
        user_stats = {}
        # Count topics per user
        topic_counts = db.query(
            ForumTopic.author_id,
            func.count(ForumTopic.id).label('count')
        ).filter(
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
        ).group_by(ForumTopic.author_id).all()

        for author_id, count in topic_counts:
            if author_id not in user_stats:
                user_stats[author_id] = {'topic_count': 0, 'reply_count': 0, 'solution_count': 0, 'reaction_count': 0}
            user_stats[author_id]['topic_count'] = count

        # Count replies per user
        reply_counts = db.query(
            ForumReply.author_id,
            func.count(ForumReply.id).label('count')
        ).filter(
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).group_by(ForumReply.author_id).all()

        for author_id, count in reply_counts:
            if author_id not in user_stats:
                user_stats[author_id] = {'topic_count': 0, 'reply_count': 0, 'solution_count': 0, 'reaction_count': 0}
            user_stats[author_id]['reply_count'] = count

        # Count solutions per user
        solution_counts = db.query(
            ForumReply.author_id,
            func.count(ForumReply.id).label('count')
        ).filter(
            ForumReply.is_solution == True,
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).group_by(ForumReply.author_id).all()

        for author_id, count in solution_counts:
            if author_id in user_stats:
                user_stats[author_id]['solution_count'] = count

        # Get user details and calculate total score
        user_rankings = []
        user_ids = list(user_stats.keys())
        if user_ids:
            users = db.query(User).filter(User.id.in_(user_ids)).all()
            user_map = {u.id: u for u in users}

            for user_id, stats_data in user_stats.items():
                if user_id in user_map:
                    user = user_map[user_id]
                    total_score = (
                        stats_data['topic_count'] * 2 +
                        stats_data['reply_count'] +
                        stats_data['solution_count'] * 5
                    )
                    user_rankings.append({
                        'id': user_id,
                        'name': user.name,
                        'email': user.email,
                        'topic_count': stats_data['topic_count'],
                        'reply_count': stats_data['reply_count'],
                        'solution_count': stats_data['solution_count'],
                        'reaction_count': stats_data['reaction_count'],
                        'total_score': total_score
                    })

        user_rankings.sort(key=lambda x: x['total_score'], reverse=True)
        user_rankings = user_rankings[:20]  # Top 20

        # Category stats
        category_stats = {}
        for cat in ForumTopic.CATEGORIES:
            count = db.query(func.count(ForumTopic.id)).filter(
                ForumTopic.category == cat,
                (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
            ).scalar() or 0
            category_stats[cat] = count

        # Chart data (activity per day)
        chart_labels = []
        chart_topics = []
        chart_replies = []

        current_date = start_date
        while current_date <= end_date:
            date_str = current_date.strftime('%d.%m')
            chart_labels.append(date_str)

            day_start = current_date.replace(hour=0, minute=0, second=0, microsecond=0)
            day_end = current_date.replace(hour=23, minute=59, second=59, microsecond=999999)

            topics_count = db.query(func.count(ForumTopic.id)).filter(
                ForumTopic.created_at >= day_start,
                ForumTopic.created_at <= day_end,
                (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
            ).scalar() or 0
            chart_topics.append(topics_count)

            replies_count = db.query(func.count(ForumReply.id)).filter(
                ForumReply.created_at >= day_start,
                ForumReply.created_at <= day_end,
                (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
            ).scalar() or 0
            chart_replies.append(replies_count)

            current_date += timedelta(days=1)

        chart_data = {
            'labels': chart_labels,
            'topics': chart_topics,
            'replies': chart_replies
        }

        return render_template(
            'admin/forum_analytics.html',
            stats=stats,
            unanswered_topics=unanswered_topics,
            user_rankings=user_rankings,
            category_stats=category_stats,
            chart_data=chart_data,
            start_date=start_date_str,
            end_date=end_date_str,
            category_labels=ForumTopic.CATEGORY_LABELS
        )
    finally:
        db.close()


@bp.route('/admin/forum/export-activity')
@login_required
def admin_forum_export_activity():
    """Export forum activity to CSV"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnien'}), 403

    from flask import Response
    from datetime import timedelta
    import csv
    import io

    # Date range from query params
    end_date_str = request.args.get('end_date', datetime.now().strftime('%Y-%m-%d'))
    start_date_str = request.args.get('start_date', (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'))

    try:
        end_date = datetime.strptime(end_date_str, '%Y-%m-%d').replace(hour=23, minute=59, second=59)
        start_date = datetime.strptime(start_date_str, '%Y-%m-%d')
    except ValueError:
        end_date = datetime.now()
        start_date = end_date - timedelta(days=30)

    db = SessionLocal()
    try:
        # Get all topics in date range
        topics = db.query(ForumTopic).filter(
            ForumTopic.created_at >= start_date,
            ForumTopic.created_at <= end_date
        ).order_by(ForumTopic.created_at.desc()).all()

        # Get all replies in date range
        replies = db.query(ForumReply).filter(
            ForumReply.created_at >= start_date,
            ForumReply.created_at <= end_date
        ).order_by(ForumReply.created_at.desc()).all()

        # Create CSV
        output = io.StringIO()
        writer = csv.writer(output)

        # Header
        writer.writerow([
            'Typ', 'ID', 'Tytul/Temat', 'Autor', 'Email', 'Kategoria',
            'Status', 'Data utworzenia', 'Odpowiedzi', 'Wyswietlenia'
        ])

        # Topics
        for topic in topics:
            reply_count = len([r for r in topic.replies if not r.is_deleted])
            writer.writerow([
                'Temat',
                topic.id,
                topic.title,
                topic.author.name or topic.author.email.split('@')[0],
                topic.author.email,
                ForumTopic.CATEGORY_LABELS.get(topic.category, topic.category),
                ForumTopic.STATUS_LABELS.get(topic.status, topic.status),
                topic.created_at.strftime('%Y-%m-%d %H:%M'),
                reply_count,
                topic.views_count or 0
            ])

        # Replies
        for reply in replies:
            writer.writerow([
                'Odpowiedz',
                reply.id,
                f'Re: {reply.topic.title}' if reply.topic else f'Temat #{reply.topic_id}',
                reply.author.name or reply.author.email.split('@')[0],
                reply.author.email,
                '',
                'Rozwiazanie' if reply.is_solution else '',
                reply.created_at.strftime('%Y-%m-%d %H:%M'),
                '',
                ''
            ])

        output.seek(0)
        filename = f'forum_activity_{start_date_str}_{end_date_str}.csv'

        return Response(
            output.getvalue(),
            mimetype='text/csv',
            headers={
                'Content-Disposition': f'attachment; filename={filename}',
                'Content-Type': 'text/csv; charset=utf-8'
            }
        )
    finally:
        db.close()


@bp.route('/admin/forum/topic/<int:topic_id>/move', methods=['POST'])
@login_required
def admin_move_topic(topic_id):
    """Move topic to different category"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnien'}), 403

    data = request.get_json() or {}
    new_category = data.get('category')

    if not new_category or new_category not in ForumTopic.CATEGORIES:
        return jsonify({'success': False, 'error': 'Nieprawidlowa kategoria'}), 400

    db = SessionLocal()
    try:
        topic = db.query(ForumTopic).filter(ForumTopic.id == topic_id).first()
        if not topic:
            return jsonify({'success': False, 'error': 'Temat nie istnieje'}), 404

        old_category = topic.category
        topic.category = new_category
        db.commit()

        logger.info(f"Admin {current_user.email} moved topic #{topic_id} from {old_category} to {new_category}")
        return jsonify({
            'success': True,
            'message': f"Temat przeniesiony do: {ForumTopic.CATEGORY_LABELS.get(new_category, new_category)}",
            'old_category': old_category,
            'new_category': new_category
        })
    finally:
        db.close()


@bp.route('/admin/forum/merge-topics', methods=['POST'])
@login_required
def admin_merge_topics():
    """Merge multiple topics into one"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnien'}), 403

    data = request.get_json() or {}
    target_id = data.get('target_id')
    source_ids = data.get('source_ids', [])

    if not target_id or not source_ids:
        return jsonify({'success': False, 'error': 'Brak wymaganych parametrow'}), 400

    # Ensure target is not in sources
    source_ids = [sid for sid in source_ids if sid != target_id]

    if not source_ids:
        return jsonify({'success': False, 'error': 'Brak tematow do polaczenia'}), 400

    db = SessionLocal()
    try:
        # Get target topic
        target = db.query(ForumTopic).filter(ForumTopic.id == target_id).first()
        if not target:
            return jsonify({'success': False, 'error': 'Temat docelowy nie istnieje'}), 404

        # Get source topics
        sources = db.query(ForumTopic).filter(ForumTopic.id.in_(source_ids)).all()
        if not sources:
            return jsonify({'success': False, 'error': 'Nie znaleziono tematow zrodlowych'}), 404

        merged_count = 0
        for source in sources:
            # Create a reply from the source topic content
            merge_note = ForumReply(
                topic_id=target_id,
                author_id=source.author_id,
                content=f"[Polaczony temat: {source.title}]\n\n{source.content}",
                created_at=source.created_at
            )
            db.add(merge_note)

            # Move all replies from source to target
            for reply in source.replies:
                reply.topic_id = target_id

            # Soft-delete the source topic
            source.is_deleted = True
            source.deleted_at = datetime.now()
            source.deleted_by = current_user.id

            merged_count += 1

        # Update target topic timestamp
        target.updated_at = datetime.now()
        db.commit()

        logger.info(f"Admin {current_user.email} merged {merged_count} topics into #{target_id}")
        return jsonify({
            'success': True,
            'message': f"Polaczono {merged_count} tematow",
            'merged_count': merged_count,
            'target_id': target_id
        })
    except Exception as e:
        db.rollback()
        logger.error(f"Error merging topics: {e}")
        return jsonify({'success': False, 'error': 'Wystapil blad podczas laczenia'}), 500
    finally:
        db.close()


@bp.route('/admin/forum/search')
@login_required
def admin_forum_search():
    """Search all forum content (including deleted) - moderators only"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnien'}), 403

    query = request.args.get('q', '').strip()
    include_deleted = request.args.get('deleted') == '1'

    if not query or len(query) < 2:
        return jsonify({
            'success': True,
            'results': [],
            'count': 0,
            'message': 'Wpisz co najmniej 2 znaki'
        })

    db = SessionLocal()
    try:
        search_term = f'%{query}%'
        results = []

        # Search topics
        topic_query = db.query(ForumTopic).filter(
            (ForumTopic.title.ilike(search_term)) |
            (ForumTopic.content.ilike(search_term))
        )

        if not include_deleted:
            topic_query = topic_query.filter(
                (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
            )

        topics = topic_query.order_by(ForumTopic.created_at.desc()).limit(50).all()

        for topic in topics:
            results.append({
                'type': 'topic',
                'id': topic.id,
                'title': topic.title,
                'content_preview': topic.content[:150] + '...' if len(topic.content) > 150 else topic.content,
                'author_name': topic.author.name or topic.author.email.split('@')[0],
                'author_id': topic.author_id,
                'created_at': topic.created_at.isoformat(),
                'is_deleted': topic.is_deleted or False,
                'category': topic.category,
                'category_label': ForumTopic.CATEGORY_LABELS.get(topic.category, topic.category),
                'url': url_for('.forum_topic', topic_id=topic.id)
            })

        # Search replies
        reply_query = db.query(ForumReply).filter(
            ForumReply.content.ilike(search_term)
        )

        if not include_deleted:
            reply_query = reply_query.filter(
                (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
            )

        replies = reply_query.order_by(ForumReply.created_at.desc()).limit(50).all()

        for reply in replies:
            results.append({
                'type': 'reply',
                'id': reply.id,
                'title': f'Re: {reply.topic.title}' if reply.topic else f'Odpowiedz #{reply.id}',
                'content_preview': reply.content[:150] + '...' if len(reply.content) > 150 else reply.content,
                'author_name': reply.author.name or reply.author.email.split('@')[0],
                'author_id': reply.author_id,
                'created_at': reply.created_at.isoformat(),
                'is_deleted': reply.is_deleted or False,
                'topic_id': reply.topic_id,
                'url': url_for('.forum_topic', topic_id=reply.topic_id) + f'#reply-{reply.id}'
            })

        # Sort by date
        results.sort(key=lambda x: x['created_at'], reverse=True)

        return jsonify({
            'success': True,
            'results': results[:100],  # Limit to 100 total results
            'count': len(results),
            'query': query
        })
    finally:
        db.close()


@bp.route('/admin/forum/user/<int:user_id>/activity')
@login_required
def admin_user_forum_activity(user_id):
    """Get detailed forum activity for a specific user - moderators only"""
    if not current_user.can_moderate_forum():
        return jsonify({'success': False, 'error': 'Brak uprawnien'}), 403

    from sqlalchemy import func

    db = SessionLocal()
    try:
        # Get user
        user = db.query(User).filter(User.id == user_id).first()
        if not user:
            return jsonify({'success': False, 'error': 'Uzytkownik nie istnieje'}), 404

        # Get user's topics
        topics = db.query(ForumTopic).filter(
            ForumTopic.author_id == user_id
        ).order_by(ForumTopic.created_at.desc()).limit(20).all()

        # Get user's replies
        replies = db.query(ForumReply).filter(
            ForumReply.author_id == user_id
        ).order_by(ForumReply.created_at.desc()).limit(30).all()

        # Stats
        topic_count = db.query(func.count(ForumTopic.id)).filter(
            ForumTopic.author_id == user_id,
            (ForumTopic.is_deleted == False) | (ForumTopic.is_deleted.is_(None))
        ).scalar() or 0

        reply_count = db.query(func.count(ForumReply.id)).filter(
            ForumReply.author_id == user_id,
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).scalar() or 0

        solution_count = db.query(func.count(ForumReply.id)).filter(
            ForumReply.author_id == user_id,
            ForumReply.is_solution == True,
            (ForumReply.is_deleted == False) | (ForumReply.is_deleted.is_(None))
        ).scalar() or 0

        # Build activity log
        activity = []

        for topic in topics:
            activity.append({
                'type': 'topic',
                'action': 'Utworzyl temat',
                'title': topic.title,
                'id': topic.id,
                'created_at': topic.created_at.isoformat(),
                'is_deleted': topic.is_deleted or False,
                'category': topic.category,
                'url': url_for('.forum_topic', topic_id=topic.id)
            })

        for reply in replies:
            activity.append({
                'type': 'reply',
                'action': 'Odpowiedzial w' if reply.is_solution else 'Odpowiedzial w',
                'title': reply.topic.title if reply.topic else f'Temat #{reply.topic_id}',
                'id': reply.id,
                'topic_id': reply.topic_id,
                'created_at': reply.created_at.isoformat(),
                'is_deleted': reply.is_deleted or False,
                'is_solution': reply.is_solution or False,
                'url': url_for('.forum_topic', topic_id=reply.topic_id) + f'#reply-{reply.id}'
            })

        # Sort by date
        activity.sort(key=lambda x: x['created_at'], reverse=True)

        return jsonify({
            'success': True,
            'user': {
                'id': user.id,
                'name': user.name or user.email.split('@')[0],
                'email': user.email
            },
            'stats': {
                'topics': topic_count,
                'replies': reply_count,
                'solutions': solution_count,
                'total_posts': topic_count + reply_count
            },
            'activity': activity[:50]  # Limit to 50 most recent
        })
    finally:
        db.close()
