"""
Editor panel routes for ScholarPress.
"""

from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app, send_from_directory
from flask_login import login_required, current_user
from functools import wraps
from datetime import datetime
import os

from app import db
from app.models import (
    Article, Journal, Tag, Submission, SubmissionStatusUpdate,
    ContactThread, ContactMessage, SiteSettings
)
from app.utils import save_file, delete_file, generate_unique_slug, allowed_file
from app.utils.email import send_submission_status_update, send_contact_reply_notification

editor_bp = Blueprint('editor', __name__)


def editor_required(f):
    """Decorator to require editor or admin role."""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated or not current_user.is_editor():
            flash('You do not have permission to access this page.', 'danger')
            return redirect(url_for('auth.login'))
        return f(*args, **kwargs)
    return decorated_function


@editor_bp.before_request
@login_required
@editor_required
def before_request():
    """Ensure all editor routes require authentication and editor role."""
    pass


# ==================== Dashboard ====================

@editor_bp.route('/')
def dashboard():
    """Editor dashboard."""
    stats = {
        'total_articles': Article.query.count(),
        'published_articles': Article.query.filter_by(is_published=True).count(),
        'pending_submissions': Submission.query.filter_by(status='submitted').count(),
        'in_review_submissions': Submission.query.filter_by(status='in_review').count(),
        'unread_messages': ContactThread.query.filter_by(is_closed=False).count()
    }
    
    recent_submissions = Submission.query.order_by(Submission.created_at.desc()).limit(5).all()
    recent_messages = ContactThread.query.order_by(ContactThread.updated_at.desc()).limit(5).all()
    
    return render_template('editor/dashboard.html',
                         stats=stats,
                         recent_submissions=recent_submissions,
                         recent_messages=recent_messages)


# ==================== Article Management ====================

@editor_bp.route('/articles')
def articles():
    """List all articles."""
    page = request.args.get('page', 1, type=int)
    status = request.args.get('status', '')
    journal_id = request.args.get('journal', type=int)
    
    query = Article.query
    
    if status == 'published':
        query = query.filter_by(is_published=True)
    elif status == 'draft':
        query = query.filter_by(is_published=False)
    
    if journal_id:
        query = query.filter_by(journal_id=journal_id)
    
    articles = query.order_by(Article.created_at.desc()).paginate(page=page, per_page=20, error_out=False)
    journals = Journal.query.order_by(Journal.name).all()
    
    return render_template('editor/articles/list.html', articles=articles, journals=journals)


@editor_bp.route('/articles/add', methods=['GET', 'POST'])
def add_article():
    """Add a new article."""
    journals = Journal.query.filter_by(is_active=True).order_by(Journal.name).all()
    all_tags = Tag.query.order_by(Tag.name).all()
    
    if request.method == 'POST':
        title = request.form.get('title', '').strip()
        abstract = request.form.get('abstract', '').strip()
        content = request.form.get('content', '').strip()
        authors = request.form.get('authors', '').strip()
        journal_id = request.form.get('journal_id', type=int)
        tag_ids = request.form.getlist('tags', type=int)
        is_published = request.form.get('is_published') == 'on'
        is_open_access = request.form.get('is_open_access') == 'on'
        meta_title = request.form.get('meta_title', '').strip()
        meta_description = request.form.get('meta_description', '').strip()
        meta_keywords = request.form.get('meta_keywords', '').strip()
        
        errors = []
        if not title:
            errors.append('Title is required.')
        if not journal_id:
            errors.append('Journal is required.')
        
        if errors:
            for error in errors:
                flash(error, 'danger')
            return render_template('editor/articles/form.html', article=None, journals=journals, all_tags=all_tags)
        
        article = Article(
            title=title,
            slug=generate_unique_slug(title, Article),
            abstract=abstract,
            content=content,
            authors=authors,
            journal_id=journal_id,
            author_id=current_user.id,
            is_published=is_published,
            is_open_access=is_open_access,
            meta_title=meta_title or title[:200],
            meta_description=meta_description or abstract[:500] if abstract else '',
            meta_keywords=meta_keywords
        )
        
        if is_published:
            article.published_date = datetime.utcnow()
        
        # Add tags
        if tag_ids:
            tags = Tag.query.filter(Tag.id.in_(tag_ids)).all()
            article.tags = tags
        
        # Handle PDF upload
        pdf_file = request.files.get('pdf_file')
        if pdf_file and pdf_file.filename:
            if allowed_file(pdf_file.filename):
                article.pdf_file = save_file(pdf_file, 'articles')
            else:
                flash('Invalid file format.', 'warning')
        
        db.session.add(article)
        db.session.commit()
        
        # Generate DOI after commit
        if is_published:
            article.doi = article.generate_doi()
            db.session.commit()
        
        flash(f'Article "{title}" created successfully.', 'success')
        return redirect(url_for('editor.articles'))
    
    return render_template('editor/articles/form.html', article=None, journals=journals, all_tags=all_tags)


@editor_bp.route('/articles/<int:id>/edit', methods=['GET', 'POST'])
def edit_article(id):
    """Edit an article."""
    article = Article.query.get_or_404(id)
    journals = Journal.query.filter_by(is_active=True).order_by(Journal.name).all()
    all_tags = Tag.query.order_by(Tag.name).all()
    
    if request.method == 'POST':
        title = request.form.get('title', '').strip()
        abstract = request.form.get('abstract', '').strip()
        content = request.form.get('content', '').strip()
        authors = request.form.get('authors', '').strip()
        journal_id = request.form.get('journal_id', type=int)
        tag_ids = request.form.getlist('tags', type=int)
        is_published = request.form.get('is_published') == 'on'
        is_open_access = request.form.get('is_open_access') == 'on'
        meta_title = request.form.get('meta_title', '').strip()
        meta_description = request.form.get('meta_description', '').strip()
        meta_keywords = request.form.get('meta_keywords', '').strip()
        
        if not title:
            flash('Title is required.', 'danger')
            return render_template('editor/articles/form.html', article=article, journals=journals, all_tags=all_tags)
        
        was_published = article.is_published
        
        article.title = title
        article.slug = generate_unique_slug(title, Article, article.id)
        article.abstract = abstract
        article.content = content
        article.authors = authors
        article.journal_id = journal_id
        article.is_published = is_published
        article.is_open_access = is_open_access
        article.meta_title = meta_title or title[:200]
        article.meta_description = meta_description or abstract[:500] if abstract else ''
        article.meta_keywords = meta_keywords
        
        if is_published and not was_published:
            article.published_date = datetime.utcnow()
            if not article.doi:
                article.doi = article.generate_doi()
        
        # Update tags
        tags = Tag.query.filter(Tag.id.in_(tag_ids)).all() if tag_ids else []
        article.tags = tags
        
        # Handle PDF upload
        pdf_file = request.files.get('pdf_file')
        if pdf_file and pdf_file.filename:
            if allowed_file(pdf_file.filename):
                if article.pdf_file:
                    delete_file(article.pdf_file)
                article.pdf_file = save_file(pdf_file, 'articles')
            else:
                flash('Invalid file format.', 'warning')
        
        db.session.commit()
        flash(f'Article "{title}" updated successfully.', 'success')
        return redirect(url_for('editor.articles'))
    
    return render_template('editor/articles/form.html', article=article, journals=journals, all_tags=all_tags)


@editor_bp.route('/articles/<int:id>/delete', methods=['POST'])
def delete_article(id):
    """Delete an article."""
    article = Article.query.get_or_404(id)
    
    if article.pdf_file:
        delete_file(article.pdf_file)
    
    db.session.delete(article)
    db.session.commit()
    flash('Article deleted successfully.', 'success')
    return redirect(url_for('editor.articles'))


# ==================== Submission Management ====================

@editor_bp.route('/submissions')
def submissions():
    """List all submissions."""
    page = request.args.get('page', 1, type=int)
    status = request.args.get('status', '')
    
    query = Submission.query
    
    if status:
        query = query.filter_by(status=status)
    
    submissions = query.order_by(Submission.created_at.desc()).paginate(page=page, per_page=15, error_out=False)
    
    return render_template('editor/submissions/list.html', submissions=submissions, current_status=status)


@editor_bp.route('/submissions/<int:id>')
def view_submission(id):
    """View submission details."""
    submission = Submission.query.get_or_404(id)
    return render_template('editor/submissions/view.html', submission=submission)


@editor_bp.route('/submissions/<int:id>/update-status', methods=['POST'])
def update_submission_status(id):
    """Update submission status."""
    submission = Submission.query.get_or_404(id)
    
    new_status = request.form.get('status', '').strip()
    notes = request.form.get('notes', '').strip()
    
    valid_statuses = ['pending', 'under_review', 'in_review', 'revision_requested', 'accepted', 'rejected', 'published']
    if new_status not in valid_statuses:
        flash('Invalid status.', 'danger')
        return redirect(url_for('editor.view_submission', id=id))
    
    old_status = submission.status
    
    if old_status != new_status:
        submission.status = new_status
        submission.admin_notes = notes
        
        status_update = SubmissionStatusUpdate(
            submission_id=submission.id,
            old_status=old_status,
            new_status=new_status,
            notes=notes,
            updated_by_id=current_user.id
        )
        db.session.add(status_update)
        db.session.commit()
        
        try:
            send_submission_status_update(
                submission, old_status, new_status, notes,
                current_app.config['SITE_URL']
            )
        except Exception as e:
            current_app.logger.error(f"Failed to send status update email: {e}")
        
        status_display = new_status.replace('_', ' ').title()
        flash(f'Submission status updated to "{status_display}".', 'success')
    else:
        flash('No status change.', 'info')
    
    return redirect(url_for('editor.view_submission', id=id))


@editor_bp.route('/submissions/<int:id>/convert', methods=['GET', 'POST'])
def convert_to_article(id):
    """Convert an accepted submission to an article."""
    submission = Submission.query.get_or_404(id)
    
    if submission.status != 'accepted':
        flash('Only accepted submissions can be converted to articles.', 'warning')
        return redirect(url_for('editor.view_submission', id=id))
    
    journals = Journal.query.filter_by(is_active=True).order_by(Journal.name).all()
    all_tags = Tag.query.order_by(Tag.name).all()
    
    if request.method == 'POST':
        title = request.form.get('title', '').strip()
        abstract = request.form.get('abstract', '').strip()
        content = request.form.get('content', '').strip()
        authors = request.form.get('authors', '').strip()
        journal_id = request.form.get('journal_id', type=int)
        tag_ids = request.form.getlist('tags', type=int)
        is_open_access = request.form.get('is_open_access') == 'on'
        meta_keywords = request.form.get('meta_keywords', '').strip()
        
        if not title or not journal_id:
            flash('Title and Journal are required.', 'danger')
            return render_template('editor/submissions/convert.html',
                                 submission=submission,
                                 journals=journals,
                                 all_tags=all_tags)
        
        article = Article(
            title=title,
            slug=generate_unique_slug(title, Article),
            abstract=abstract,
            content=content,
            authors=authors,
            journal_id=journal_id,
            author_id=current_user.id,
            submission_id=submission.id,
            is_published=True,
            is_open_access=is_open_access,
            published_date=datetime.utcnow(),
            meta_title=title[:200],
            meta_description=abstract[:500] if abstract else '',
            meta_keywords=meta_keywords,
            pdf_file=submission.file_path
        )
        
        if tag_ids:
            tags = Tag.query.filter(Tag.id.in_(tag_ids)).all()
            article.tags = tags
        
        db.session.add(article)
        db.session.commit()
        
        article.doi = article.generate_doi()
        db.session.commit()
        
        flash(f'Article "{title}" created from submission.', 'success')
        return redirect(url_for('editor.articles'))
    
    return render_template('editor/submissions/convert.html',
                         submission=submission,
                         journals=journals,
                         all_tags=all_tags)


@editor_bp.route('/submissions/<int:id>/download')
def download_submission_file(id):
    """Download submission file."""
    submission = Submission.query.get_or_404(id)
    
    upload_folder = current_app.config['UPLOAD_FOLDER']
    file_path = os.path.dirname(submission.file_path)
    filename = os.path.basename(submission.file_path)
    
    return send_from_directory(
        os.path.join(upload_folder, file_path),
        filename,
        as_attachment=True
    )


# ==================== Contact Message Management ====================

@editor_bp.route('/messages')
def messages():
    """List all contact threads."""
    page = request.args.get('page', 1, type=int)
    status = request.args.get('status', '')
    
    query = ContactThread.query
    
    if status == 'open':
        query = query.filter_by(is_closed=False)
    elif status == 'closed':
        query = query.filter_by(is_closed=True)
    
    threads = query.order_by(ContactThread.updated_at.desc()).paginate(page=page, per_page=20, error_out=False)
    
    return render_template('editor/messages/list.html', threads=threads, current_status=status)


@editor_bp.route('/messages/<int:id>', methods=['GET', 'POST'])
def view_message(id):
    """View and reply to a contact thread."""
    thread = ContactThread.query.get_or_404(id)
    
    if request.method == 'POST':
        action = request.form.get('action', '')
        
        if action == 'reply':
            message_text = request.form.get('message', '').strip()
            
            if not message_text:
                flash('Reply message cannot be empty.', 'danger')
                return redirect(url_for('editor.view_message', id=id))
            
            message = ContactMessage(
                thread_id=thread.id,
                message=message_text,
                is_from_user=False,
                responder_id=current_user.id
            )
            db.session.add(message)
            thread.updated_at = datetime.utcnow()
            db.session.commit()
            
            try:
                send_contact_reply_notification(thread, message, current_app.config['SITE_URL'])
            except Exception as e:
                current_app.logger.error(f"Failed to send reply notification: {e}")
            
            flash('Reply sent successfully.', 'success')
        
        elif action == 'close':
            thread.is_closed = True
            db.session.commit()
            flash('Conversation closed.', 'info')
        
        elif action == 'reopen':
            thread.is_closed = False
            db.session.commit()
            flash('Conversation reopened.', 'info')
        
        return redirect(url_for('editor.view_message', id=id))
    
    messages = thread.messages.all()
    return render_template('editor/messages/view.html', thread=thread, messages=messages)
