"""
GJEE Journal Clone - Flask Application
A dynamic clone of the Global Journal of Engineering Education website
with admin panel for managing users, editors, issues, and contributions.
"""

import os
import secrets
from datetime import datetime
from functools import wraps
from werkzeug.utils import secure_filename
from werkzeug.security import generate_password_hash, check_password_hash
from flask import (
    Flask, render_template, request, redirect, url_for, 
    flash, session, send_from_directory, abort
)
from flask_sqlalchemy import SQLAlchemy

# Initialize Flask app
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(32)
if os.name == "posix":
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://tezloans_gjee:TESTdata123@148.113.4.193/tezloans_gjee'
else:
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///gjee.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
    'pool_pre_ping': True,
    'pool_recycle': 25
}
app.config['UPLOAD_FOLDER'] = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max file size
app.config['ALLOWED_EXTENSIONS'] = {'pdf', 'docx', 'doc', 'txt'}

# Ensure upload folder exists
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

# Initialize database
db = SQLAlchemy(app)


# ===================== DATABASE MODELS =====================

class User(db.Model):
    """Admin users for the system"""
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(256), nullable=False)
    is_admin = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
    
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)


class Editor(db.Model):
    """Editorial board members"""
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200), nullable=False)
    title = db.Column(db.String(100))  # Prof., Dr., A/Prof., etc.
    role = db.Column(db.String(100), nullable=False)  # Editor-in-Chief, Associate Editor, etc.
    affiliation = db.Column(db.Text)
    email = db.Column(db.String(120))
    order = db.Column(db.Integer, default=0)  # For display ordering
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


class Volume(db.Model):
    """Journal volumes"""
    id = db.Column(db.Integer, primary_key=True)
    volume_number = db.Column(db.Integer, nullable=False)
    year = db.Column(db.Integer, nullable=False)
    is_current = db.Column(db.Boolean, default=True)  # True for current, False for back issues
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    issues = db.relationship('Issue', backref='volume', lazy=True, cascade='all, delete-orphan')


class Issue(db.Model):
    """Journal issues within a volume"""
    id = db.Column(db.Integer, primary_key=True)
    volume_id = db.Column(db.Integer, db.ForeignKey('volume.id'), nullable=False)
    issue_number = db.Column(db.Integer, nullable=False)
    title = db.Column(db.String(200))  # e.g., "Vol.27, No.1 (2025)"
    published = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    articles = db.relationship('Article', backref='issue', lazy=True, cascade='all, delete-orphan')
    
    @property
    def display_name(self):
        return f"Vol.{self.volume.volume_number}, No.{self.issue_number} ({self.volume.year})"


class Article(db.Model):
    """Published articles in issues"""
    id = db.Column(db.Integer, primary_key=True)
    issue_id = db.Column(db.Integer, db.ForeignKey('issue.id'), nullable=False)
    title = db.Column(db.Text, nullable=False)
    authors = db.Column(db.Text, nullable=False)
    abstract = db.Column(db.Text)  # Abstract for Google Scholar indexing
    pages = db.Column(db.String(50))
    pdf_filename = db.Column(db.String(255))
    doi = db.Column(db.String(100))  # Digital Object Identifier
    order = db.Column(db.Integer, default=0)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


class Contribution(db.Model):
    """User-submitted contributions (Call for Contributions)"""
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.Text, nullable=False)
    authors = db.Column(db.Text, nullable=False)
    abstract = db.Column(db.Text, nullable=False)
    email = db.Column(db.String(120), nullable=False)
    filename = db.Column(db.String(255), nullable=False)
    original_filename = db.Column(db.String(255), nullable=False)
    status = db.Column(db.String(50), default='pending')  # pending, reviewed, accepted, rejected
    submitted_at = db.Column(db.DateTime, default=datetime.utcnow)
    notes = db.Column(db.Text)  # Admin notes


class SiteContent(db.Model):
    """Dynamic site content (about, objectives, notes for contributors, contact info)"""
    id = db.Column(db.Integer, primary_key=True)
    key = db.Column(db.String(100), unique=True, nullable=False)
    title = db.Column(db.String(200))
    content = db.Column(db.Text)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)


# ===================== HELPER FUNCTIONS =====================

def allowed_file(filename):
    """Check if file extension is allowed"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']


def login_required(f):
    """Decorator to require login for admin routes"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session:
            flash('Please log in to access this page.', 'warning')
            return redirect(url_for('admin_login'))
        return f(*args, **kwargs)
    return decorated_function


def get_site_content(key, default_content=''):
    """Get content from database or return default"""
    content = SiteContent.query.filter_by(key=key).first()
    return content.content if content else default_content


# ===================== CONTEXT PROCESSORS =====================

@app.context_processor
def utility_processor():
    """Make utility functions available in templates"""
    return {
        'current_year': datetime.now().year,
        'get_site_content': get_site_content,
        'now': datetime.utcnow  # For OAI-PMH timestamps
    }


# ===================== FRONTEND ROUTES =====================

@app.route('/')
def index():
    """Home page - About the GJEE"""
    content = SiteContent.query.filter_by(key='about').first()
    return render_template('frontend/index.html', content=content)


@app.route('/objectives')
def objectives():
    """Objectives page"""
    content = SiteContent.query.filter_by(key='objectives').first()
    return render_template('frontend/objectives.html', content=content)


@app.route('/editorial-board')
def editorial_board():
    """Editorial Advisory Board page"""
    editors = Editor.query.order_by(Editor.order, Editor.id).all()
    
    # Group editors by role
    editor_groups = {
        'Editor-in-Chief': [],
        'Manager & Associate Editor': [],
        'Associate Editors': [],
        'Advisory Board Members': []
    }
    
    for editor in editors:
        if editor.role in editor_groups:
            editor_groups[editor.role].append(editor)
        else:
            editor_groups['Advisory Board Members'].append(editor)
    
    return render_template('frontend/editorial_board.html', editor_groups=editor_groups)


@app.route('/notes-for-contributors')
def notes_for_contributors():
    """Notes for Contributors page"""
    content = SiteContent.query.filter_by(key='notes').first()
    return render_template('frontend/notes_for_contributors.html', content=content)


@app.route('/call-for-contributions', methods=['GET', 'POST'])
def call_for_contributions():
    """Call for Contributions - submission form"""
    if request.method == 'POST':
        # Validate form data
        title = request.form.get('title', '').strip()
        authors = request.form.get('authors', '').strip()
        abstract = request.form.get('abstract', '').strip()
        email = request.form.get('email', '').strip()
        
        if not all([title, authors, abstract, email]):
            flash('All fields are required.', 'error')
            return redirect(url_for('call_for_contributions'))
        
        # Handle file upload
        if 'paper' not in request.files:
            flash('Please upload your paper.', 'error')
            return redirect(url_for('call_for_contributions'))
        
        file = request.files['paper']
        if file.filename == '':
            flash('Please select a file to upload.', 'error')
            return redirect(url_for('call_for_contributions'))
        
        if not allowed_file(file.filename):
            flash('Invalid file type. Please upload PDF, DOCX, or TXT files.', 'error')
            return redirect(url_for('call_for_contributions'))
        
        # Save file with unique name
        original_filename = secure_filename(file.filename)
        unique_filename = f"{datetime.now().strftime('%Y%m%d%H%M%S')}_{secrets.token_hex(8)}_{original_filename}"
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
        file.save(file_path)
        
        # Save contribution to database
        contribution = Contribution(
            title=title,
            authors=authors,
            abstract=abstract,
            email=email,
            filename=unique_filename,
            original_filename=original_filename
        )
        db.session.add(contribution)
        db.session.commit()
        
        flash('Your contribution has been submitted successfully! We will review it and get back to you.', 'success')
        return redirect(url_for('call_for_contributions'))
    
    return render_template('frontend/call_for_contributions.html')


@app.route('/current-issues')
def current_issues():
    """Current Issues page (2010 onwards)"""
    volumes = Volume.query.filter_by(is_current=True).order_by(Volume.year.desc(), Volume.volume_number.desc()).all()
    return render_template('frontend/current_issues.html', volumes=volumes)


@app.route('/back-issues')
def back_issues():
    """Back Issues page (1997-2007)"""
    volumes = Volume.query.filter_by(is_current=False).order_by(Volume.year.desc(), Volume.volume_number.desc()).all()
    return render_template('frontend/back_issues.html', volumes=volumes)


@app.route('/issue/<int:issue_id>')
def view_issue(issue_id):
    """View a specific issue with its articles"""
    issue = Issue.query.get_or_404(issue_id)
    articles = Article.query.filter_by(issue_id=issue_id).order_by(Article.order, Article.id).all()
    return render_template('frontend/view_issue.html', issue=issue, articles=articles)


@app.route('/contact')
def contact():
    """Contact page"""
    content = SiteContent.query.filter_by(key='contact').first()
    return render_template('frontend/contact.html', content=content)


@app.route('/article/<int:article_id>')
def view_article(article_id):
    """View a single article with full metadata for Google Scholar indexing"""
    article = Article.query.get_or_404(article_id)
    return render_template('frontend/view_article.html', article=article)


# ===================== SEO & INDEXING ROUTES =====================

@app.route('/robots.txt')
def robots():
    """Robots.txt for search engine crawlers"""
    content = """# Robots.txt for Global Journal of Engineering Education (GJEE)
# Allow all search engines to crawl the site

User-agent: *
Allow: /

# Disallow admin area
Disallow: /admin/

# Allow Google Scholar bot
User-agent: Googlebot
Allow: /

User-agent: Googlebot-Scholar
Allow: /

# Sitemap location
Sitemap: {}/sitemap.xml
""".format(request.url_root.rstrip('/'))
    
    response = app.response_class(
        response=content,
        status=200,
        mimetype='text/plain'
    )
    return response


@app.route('/sitemap.xml')
def sitemap():
    """XML Sitemap for search engines"""
    pages = []
    
    # Static pages
    static_pages = [
        ('index', 1.0, 'weekly'),
        ('objectives', 0.8, 'monthly'),
        ('editorial_board', 0.8, 'monthly'),
        ('notes_for_contributors', 0.7, 'monthly'),
        ('call_for_contributions', 0.7, 'weekly'),
        ('current_issues', 0.9, 'weekly'),
        ('back_issues', 0.8, 'monthly'),
        ('contact', 0.5, 'monthly'),
    ]
    
    for page, priority, changefreq in static_pages:
        pages.append({
            'loc': url_for(page, _external=True),
            'priority': priority,
            'changefreq': changefreq
        })
    
    # Issue pages
    issues = Issue.query.filter_by(published=True).all()
    for issue in issues:
        pages.append({
            'loc': url_for('view_issue', issue_id=issue.id, _external=True),
            'priority': 0.8,
            'changefreq': 'monthly'
        })
    
    # Article pages
    articles = Article.query.join(Issue).filter(Issue.published == True).all()
    for article in articles:
        pages.append({
            'loc': url_for('view_article', article_id=article.id, _external=True),
            'priority': 0.9,
            'changefreq': 'yearly'
        })
    
    sitemap_xml = render_template('sitemap.xml', pages=pages)
    response = app.response_class(
        response=sitemap_xml,
        status=200,
        mimetype='application/xml'
    )
    return response


@app.route('/oai')
def oai_pmh():
    """OAI-PMH endpoint for academic indexers (simplified implementation)
    This provides basic Dublin Core metadata for harvesters like BASE, OpenAIRE, etc.
    """
    verb = request.args.get('verb', 'Identify')
    
    if verb == 'Identify':
        return render_template('oai/identify.xml'), 200, {'Content-Type': 'application/xml'}
    elif verb == 'ListMetadataFormats':
        return render_template('oai/list_metadata_formats.xml'), 200, {'Content-Type': 'application/xml'}
    elif verb == 'ListRecords' or verb == 'ListIdentifiers':
        articles = Article.query.join(Issue).filter(Issue.published == True).all()
        return render_template('oai/list_records.xml', articles=articles, verb=verb), 200, {'Content-Type': 'application/xml'}
    elif verb == 'GetRecord':
        identifier = request.args.get('identifier', '')
        if identifier.startswith('oai:gjee:article/'):
            article_id = int(identifier.replace('oai:gjee:article/', ''))
            article = Article.query.get_or_404(article_id)
            return render_template('oai/get_record.xml', article=article), 200, {'Content-Type': 'application/xml'}
    
    return render_template('oai/error.xml', error='badVerb'), 400, {'Content-Type': 'application/xml'}


# ===================== ADMIN ROUTES =====================

@app.route('/admin/login', methods=['GET', 'POST'])
def admin_login():
    """Admin login page"""
    if 'user_id' in session:
        return redirect(url_for('admin_dashboard'))
    
    if request.method == 'POST':
        username = request.form.get('username', '').strip()
        password = request.form.get('password', '')
        
        user = User.query.filter_by(username=username).first()
        
        if user and user.check_password(password):
            session['user_id'] = user.id
            session['username'] = user.username
            session['is_admin'] = user.is_admin
            flash('Welcome back!', 'success')
            return redirect(url_for('admin_dashboard'))
        
        flash('Invalid username or password.', 'error')
    
    return render_template('admin/login.html')


@app.route('/admin/logout')
def admin_logout():
    """Admin logout"""
    session.clear()
    flash('You have been logged out.', 'info')
    return redirect(url_for('admin_login'))


@app.route('/admin')
@app.route('/admin/dashboard')
@login_required
def admin_dashboard():
    """Admin dashboard"""
    stats = {
        'users': User.query.count(),
        'editors': Editor.query.count(),
        'volumes': Volume.query.count(),
        'issues': Issue.query.count(),
        'articles': Article.query.count(),
        'contributions': Contribution.query.count(),
        'pending_contributions': Contribution.query.filter_by(status='pending').count()
    }
    recent_contributions = Contribution.query.order_by(Contribution.submitted_at.desc()).limit(5).all()
    return render_template('admin/dashboard.html', stats=stats, recent_contributions=recent_contributions)


# ---- User Management ----

@app.route('/admin/users')
@login_required
def admin_users():
    """List all admin users"""
    users = User.query.order_by(User.created_at.desc()).all()
    return render_template('admin/users.html', users=users)


@app.route('/admin/users/add', methods=['GET', 'POST'])
@login_required
def admin_add_user():
    """Add new admin user"""
    if request.method == 'POST':
        username = request.form.get('username', '').strip()
        email = request.form.get('email', '').strip()
        password = request.form.get('password', '')
        is_admin = request.form.get('is_admin') == 'on'
        
        if User.query.filter_by(username=username).first():
            flash('Username already exists.', 'error')
            return redirect(url_for('admin_add_user'))
        
        if User.query.filter_by(email=email).first():
            flash('Email already exists.', 'error')
            return redirect(url_for('admin_add_user'))
        
        user = User(username=username, email=email, is_admin=is_admin)
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        
        flash('User added successfully!', 'success')
        return redirect(url_for('admin_users'))
    
    return render_template('admin/user_form.html', user=None, action='Add')


@app.route('/admin/users/edit/<int:user_id>', methods=['GET', 'POST'])
@login_required
def admin_edit_user(user_id):
    """Edit admin user"""
    user = User.query.get_or_404(user_id)
    
    if request.method == 'POST':
        user.username = request.form.get('username', '').strip()
        user.email = request.form.get('email', '').strip()
        user.is_admin = request.form.get('is_admin') == 'on'
        
        new_password = request.form.get('password', '')
        if new_password:
            user.set_password(new_password)
        
        db.session.commit()
        flash('User updated successfully!', 'success')
        return redirect(url_for('admin_users'))
    
    return render_template('admin/user_form.html', user=user, action='Edit')


@app.route('/admin/users/delete/<int:user_id>', methods=['POST'])
@login_required
def admin_delete_user(user_id):
    """Delete admin user"""
    if user_id == session.get('user_id'):
        flash('You cannot delete your own account.', 'error')
        return redirect(url_for('admin_users'))
    
    user = User.query.get_or_404(user_id)
    db.session.delete(user)
    db.session.commit()
    flash('User deleted successfully!', 'success')
    return redirect(url_for('admin_users'))


# ---- Editor Management ----

@app.route('/admin/editors')
@login_required
def admin_editors():
    """List all editors"""
    editors = Editor.query.order_by(Editor.order, Editor.id).all()
    return render_template('admin/editors.html', editors=editors)


@app.route('/admin/editors/add', methods=['GET', 'POST'])
@login_required
def admin_add_editor():
    """Add new editor"""
    if request.method == 'POST':
        editor = Editor(
            name=request.form.get('name', '').strip(),
            title=request.form.get('title', '').strip(),
            role=request.form.get('role', '').strip(),
            affiliation=request.form.get('affiliation', '').strip(),
            email=request.form.get('email', '').strip(),
            order=int(request.form.get('order', 0))
        )
        db.session.add(editor)
        db.session.commit()
        flash('Editor added successfully!', 'success')
        return redirect(url_for('admin_editors'))
    
    return render_template('admin/editor_form.html', editor=None, action='Add')


@app.route('/admin/editors/edit/<int:editor_id>', methods=['GET', 'POST'])
@login_required
def admin_edit_editor(editor_id):
    """Edit editor"""
    editor = Editor.query.get_or_404(editor_id)
    
    if request.method == 'POST':
        editor.name = request.form.get('name', '').strip()
        editor.title = request.form.get('title', '').strip()
        editor.role = request.form.get('role', '').strip()
        editor.affiliation = request.form.get('affiliation', '').strip()
        editor.email = request.form.get('email', '').strip()
        editor.order = int(request.form.get('order', 0))
        
        db.session.commit()
        flash('Editor updated successfully!', 'success')
        return redirect(url_for('admin_editors'))
    
    return render_template('admin/editor_form.html', editor=editor, action='Edit')


@app.route('/admin/editors/delete/<int:editor_id>', methods=['POST'])
@login_required
def admin_delete_editor(editor_id):
    """Delete editor"""
    editor = Editor.query.get_or_404(editor_id)
    db.session.delete(editor)
    db.session.commit()
    flash('Editor deleted successfully!', 'success')
    return redirect(url_for('admin_editors'))


# ---- Volume & Issue Management ----

@app.route('/admin/volumes')
@login_required
def admin_volumes():
    """List all volumes"""
    volumes = Volume.query.order_by(Volume.year.desc(), Volume.volume_number.desc()).all()
    return render_template('admin/volumes.html', volumes=volumes)


@app.route('/admin/volumes/add', methods=['GET', 'POST'])
@login_required
def admin_add_volume():
    """Add new volume"""
    if request.method == 'POST':
        volume = Volume(
            volume_number=int(request.form.get('volume_number', 1)),
            year=int(request.form.get('year', datetime.now().year)),
            is_current=request.form.get('is_current') == 'on'
        )
        db.session.add(volume)
        db.session.commit()
        flash('Volume added successfully!', 'success')
        return redirect(url_for('admin_volumes'))
    
    return render_template('admin/volume_form.html', volume=None, action='Add')


@app.route('/admin/volumes/edit/<int:volume_id>', methods=['GET', 'POST'])
@login_required
def admin_edit_volume(volume_id):
    """Edit volume"""
    volume = Volume.query.get_or_404(volume_id)
    
    if request.method == 'POST':
        volume.volume_number = int(request.form.get('volume_number', 1))
        volume.year = int(request.form.get('year', datetime.now().year))
        volume.is_current = request.form.get('is_current') == 'on'
        
        db.session.commit()
        flash('Volume updated successfully!', 'success')
        return redirect(url_for('admin_volumes'))
    
    return render_template('admin/volume_form.html', volume=volume, action='Edit')


@app.route('/admin/volumes/delete/<int:volume_id>', methods=['POST'])
@login_required
def admin_delete_volume(volume_id):
    """Delete volume and all its issues"""
    volume = Volume.query.get_or_404(volume_id)
    db.session.delete(volume)
    db.session.commit()
    flash('Volume and all its issues deleted successfully!', 'success')
    return redirect(url_for('admin_volumes'))


@app.route('/admin/issues/<int:volume_id>')
@login_required
def admin_issues(volume_id):
    """List issues for a volume"""
    volume = Volume.query.get_or_404(volume_id)
    issues = Issue.query.filter_by(volume_id=volume_id).order_by(Issue.issue_number).all()
    return render_template('admin/issues.html', volume=volume, issues=issues)


@app.route('/admin/issues/add/<int:volume_id>', methods=['GET', 'POST'])
@login_required
def admin_add_issue(volume_id):
    """Add new issue to a volume"""
    volume = Volume.query.get_or_404(volume_id)
    
    if request.method == 'POST':
        issue = Issue(
            volume_id=volume_id,
            issue_number=int(request.form.get('issue_number', 1)),
            title=request.form.get('title', '').strip(),
            published=request.form.get('published') == 'on'
        )
        db.session.add(issue)
        db.session.commit()
        flash('Issue added successfully!', 'success')
        return redirect(url_for('admin_issues', volume_id=volume_id))
    
    return render_template('admin/issue_form.html', volume=volume, issue=None, action='Add')


@app.route('/admin/issues/edit/<int:issue_id>', methods=['GET', 'POST'])
@login_required
def admin_edit_issue(issue_id):
    """Edit issue"""
    issue = Issue.query.get_or_404(issue_id)
    
    if request.method == 'POST':
        issue.issue_number = int(request.form.get('issue_number', 1))
        issue.title = request.form.get('title', '').strip()
        issue.published = request.form.get('published') == 'on'
        
        db.session.commit()
        flash('Issue updated successfully!', 'success')
        return redirect(url_for('admin_issues', volume_id=issue.volume_id))
    
    return render_template('admin/issue_form.html', volume=issue.volume, issue=issue, action='Edit')


@app.route('/admin/issues/delete/<int:issue_id>', methods=['POST'])
@login_required
def admin_delete_issue(issue_id):
    """Delete issue and all its articles"""
    issue = Issue.query.get_or_404(issue_id)
    volume_id = issue.volume_id
    db.session.delete(issue)
    db.session.commit()
    flash('Issue and all its articles deleted successfully!', 'success')
    return redirect(url_for('admin_issues', volume_id=volume_id))


# ---- Article Management ----

@app.route('/admin/articles/<int:issue_id>')
@login_required
def admin_articles(issue_id):
    """List articles for an issue"""
    issue = Issue.query.get_or_404(issue_id)
    articles = Article.query.filter_by(issue_id=issue_id).order_by(Article.order, Article.id).all()
    return render_template('admin/articles.html', issue=issue, articles=articles)


@app.route('/admin/articles/add/<int:issue_id>', methods=['GET', 'POST'])
@login_required
def admin_add_article(issue_id):
    """Add new article to an issue"""
    issue = Issue.query.get_or_404(issue_id)
    
    if request.method == 'POST':
        pdf_filename = None
        if 'pdf' in request.files:
            file = request.files['pdf']
            if file.filename and allowed_file(file.filename):
                pdf_filename = secure_filename(file.filename)
                file.save(os.path.join(app.config['UPLOAD_FOLDER'], pdf_filename))
        
        article = Article(
            issue_id=issue_id,
            title=request.form.get('title', '').strip(),
            authors=request.form.get('authors', '').strip(),
            abstract=request.form.get('abstract', '').strip() or None,
            pages=request.form.get('pages', '').strip(),
            doi=request.form.get('doi', '').strip() or None,
            pdf_filename=pdf_filename,
            order=int(request.form.get('order', 0))
        )
        db.session.add(article)
        db.session.commit()
        flash('Article added successfully!', 'success')
        return redirect(url_for('admin_articles', issue_id=issue_id))
    
    return render_template('admin/article_form.html', issue=issue, article=None, action='Add')


@app.route('/admin/articles/edit/<int:article_id>', methods=['GET', 'POST'])
@login_required
def admin_edit_article(article_id):
    """Edit article"""
    article = Article.query.get_or_404(article_id)
    
    if request.method == 'POST':
        article.title = request.form.get('title', '').strip()
        article.authors = request.form.get('authors', '').strip()
        article.abstract = request.form.get('abstract', '').strip() or None
        article.pages = request.form.get('pages', '').strip()
        article.doi = request.form.get('doi', '').strip() or None
        article.order = int(request.form.get('order', 0))
        
        if 'pdf' in request.files:
            file = request.files['pdf']
            if file.filename and allowed_file(file.filename):
                # Delete old file if exists
                if article.pdf_filename:
                    old_path = os.path.join(app.config['UPLOAD_FOLDER'], article.pdf_filename)
                    if os.path.exists(old_path):
                        os.remove(old_path)
                
                article.pdf_filename = secure_filename(file.filename)
                file.save(os.path.join(app.config['UPLOAD_FOLDER'], article.pdf_filename))
        
        db.session.commit()
        flash('Article updated successfully!', 'success')
        return redirect(url_for('admin_articles', issue_id=article.issue_id))
    
    return render_template('admin/article_form.html', issue=article.issue, article=article, action='Edit')


@app.route('/admin/articles/delete/<int:article_id>', methods=['POST'])
@login_required
def admin_delete_article(article_id):
    """Delete article"""
    article = Article.query.get_or_404(article_id)
    issue_id = article.issue_id
    
    # Delete PDF file if exists
    if article.pdf_filename:
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], article.pdf_filename)
        if os.path.exists(file_path):
            os.remove(file_path)
    
    db.session.delete(article)
    db.session.commit()
    flash('Article deleted successfully!', 'success')
    return redirect(url_for('admin_articles', issue_id=issue_id))


# ---- Contribution Management ----

@app.route('/admin/contributions')
@login_required
def admin_contributions():
    """List all contributions"""
    status_filter = request.args.get('status', 'all')
    
    if status_filter == 'all':
        contributions = Contribution.query.order_by(Contribution.submitted_at.desc()).all()
    else:
        contributions = Contribution.query.filter_by(status=status_filter).order_by(Contribution.submitted_at.desc()).all()
    
    return render_template('admin/contributions.html', contributions=contributions, status_filter=status_filter)


@app.route('/admin/contributions/view/<int:contribution_id>')
@login_required
def admin_view_contribution(contribution_id):
    """View contribution details"""
    contribution = Contribution.query.get_or_404(contribution_id)
    return render_template('admin/contribution_view.html', contribution=contribution)


@app.route('/admin/contributions/download/<int:contribution_id>')
@login_required
def admin_download_contribution(contribution_id):
    """Download contribution file"""
    contribution = Contribution.query.get_or_404(contribution_id)
    return send_from_directory(
        app.config['UPLOAD_FOLDER'], 
        contribution.filename,
        as_attachment=True,
        download_name=contribution.original_filename
    )


@app.route('/admin/contributions/update-status/<int:contribution_id>', methods=['POST'])
@login_required
def admin_update_contribution_status(contribution_id):
    """Update contribution status"""
    contribution = Contribution.query.get_or_404(contribution_id)
    contribution.status = request.form.get('status', 'pending')
    contribution.notes = request.form.get('notes', '')
    db.session.commit()
    flash('Contribution status updated!', 'success')
    return redirect(url_for('admin_view_contribution', contribution_id=contribution_id))


@app.route('/admin/contributions/delete/<int:contribution_id>', methods=['POST'])
@login_required
def admin_delete_contribution(contribution_id):
    """Delete contribution"""
    contribution = Contribution.query.get_or_404(contribution_id)
    
    # Delete uploaded file
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], contribution.filename)
    if os.path.exists(file_path):
        os.remove(file_path)
    
    db.session.delete(contribution)
    db.session.commit()
    flash('Contribution deleted successfully!', 'success')
    return redirect(url_for('admin_contributions'))


# ---- Content Management ----

@app.route('/admin/content')
@login_required
def admin_content():
    """Manage site content"""
    contents = SiteContent.query.all()
    return render_template('admin/content.html', contents=contents)


@app.route('/admin/content/edit/<key>', methods=['GET', 'POST'])
@login_required
def admin_edit_content(key):
    """Edit site content"""
    content = SiteContent.query.filter_by(key=key).first()
    
    if not content:
        content = SiteContent(key=key)
    
    if request.method == 'POST':
        content.title = request.form.get('title', '').strip()
        content.content = request.form.get('content', '')
        
        if not content.id:
            db.session.add(content)
        
        db.session.commit()
        flash('Content updated successfully!', 'success')
        return redirect(url_for('admin_content'))
    
    return render_template('admin/content_form.html', content=content, key=key)


# ===================== FILE SERVING =====================

@app.route('/uploads/<filename>')
def uploaded_file(filename):
    """Serve uploaded files"""
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)


# ===================== ERROR HANDLERS =====================

@app.errorhandler(404)
def not_found_error(error):
    return render_template('errors/404.html'), 404


@app.errorhandler(500)
def internal_error(error):
    db.session.rollback()
    return render_template('errors/500.html'), 500


# ===================== INITIALIZATION =====================

def init_db():
    """Initialize the database with default content"""
    with app.app_context():
        db.create_all()
        
        # Create default admin user if none exists
        if not User.query.first():
            admin = User(username='admin', email='admin@gjee.org', is_admin=True)
            admin.set_password('admin123')
            db.session.add(admin)
        
        # Create default site content if none exists
        default_contents = {
            'about': {
                'title': 'Global Journal of Engineering Education (GJEE)',
                'content': '''<p>The <em>Global Journal of Engineering Education</em> (GJEE) is included in the Scopus journal citation index, one of the products of Elsevier, the world's leading multinational publisher of science and health information. This represents a step forward in our persistent endeavour to make the Journal available to a wider global community. As widely known by the scholarly international community, the SciVerse Scopus abstract and citation database is the largest of its kind as it includes close to 40,000 titles.</p>
<p>&nbsp;</p>
<p>Also, the GJEE is included in the list of journals generated by the Australian Research Council (ARC) under the Excellence in Research for Australia (ERA) initiative. The paramount objective of the ERA initiative was to launch a journal ranking list on a discipline-specific basis to evaluate research excellence and research impact.</p>'''
            },
            'objectives': {
                'title': 'Objectives of the GJEE',
                'content': '''<p>The centrepiece of WIETE's commission is human resources development within engineering through engineering education, a dual brief in its concern with the two principal facets of education: teachers and students - the instructors and future practitioners of engineering. To this end, the Institute's work involves the development of pedagogy, through research and development of courseware, software and teaching methodologies, as well as of engineering curricula, in consultation with industry, the primary employer of engineers.</p>
<p>WIETE's sphere of interest is global. The implications of such a brief are huge - most clearly, though by no means exclusively - in the impact of such work in developing countries: engineers are the innovators and realisers of technological and industrial development, from which so many material benefits derive.</p>
<p>The Institute serves the international engineering and technology community by promoting and carrying out research and development activities, providing expertise in, and improving the quality of, engineering and technology education (curricula and teaching methodologies) in Australia and abroad, to meet the needs of industry better. Within the scope of the journal are educational developments and innovations in all fields of technological sciences, including architecture, urbanisation and agriculture, to name a few.</p>
<p>Its mission is the empowerment of developing nations to achieve technical development and economic progress. Its <em>modus operandi</em> is both to facilitate the exchange between institutions and individuals of information, expertise and research on textbooks, engineering teaching courseware, software, teaching methodologies and equipment utilised in engineering and technology education; and to transfer this knowledge from developed to developing countries.</p>
<p>In its role as an international hub of engineering and technology education information and resources, the WIETE continues to publish the <em>Global Journal of Engineering Education</em> (GJEE) established by its predecessor, the UNESCO International Centre for Engineering Education in 1997, with the principal objective of providing the international engineering education community with a forum for discussion and the exchange of information on engineering education and industrial training at tertiary level.</p>
<p>It is envisaged that each annual volume of GJEE will consist of 3-4 issues, depending on the quality of articles submitted.</p>'''
            },
            'notes': {
                'title': 'Notes for Contributors',
                'content': '''<p><strong>Submitting articles</strong></p>
<p>Send articles to be considered for inclusion to the Editor-in-Chief. Original articles (i.e. not previously published) will be considered for publication. In submitting the articles, authors are required to transfer copyright to the publisher. Contributions other than academic articles are also welcome, e.g. Reviews, Policy Statements and Letters to the Editor. All contributions must be in English. Articles also should include an abstract of about 160 words.</p>
<p>The publisher's policy is that full publication payment <strong>must</strong> accompany the submission of the article. This amount will be credited to the first author's <em>account</em> maintained by the publisher. If the article is not accepted for publication, the payment will be refunded in full.</p>
<p>Potential contributors should note that the publisher reserves the right not to accept articles that in the Editor-in-Chief's view extend beyond the scope of the Journal and/or contain material that may jeopardise the quality and reputation of the Journal. Further, the publisher reserves the right to suspend or cancel publication of the Journal due to any unforeseen events or circumstances. In such circumstances, all publication payments held by the publisher will be refunded in full.</p>
<p>All communication will be done electronically. Submissions should be sent via email, and all subsequent communication will also be conducted electronically. Unless otherwise specified, the first-named author will receive the proofs for corrections of typesetting errors. Changes other than typesetting corrections will not be allowed.</p>
<p>Once your article is accepted for publication, our processes are highly efficient and the dedicated WIETE team can ensure that your article is published in approximately 6-8 weeks from the deadline for submissions.</p>
<p><strong>Journal Style</strong></p>
<p>In preparing articles for submission, authors are asked to adhere strictly to the Journal style file and instructions supplied by the publisher to ensure consistency and uniform appearance of the articles. The Journal follows the International System of Units (SI), and the standard UK English spelling. Articles will be fully edited and English corrected to ensure standard English form and expression.</p>
<p>Number illustrations consecutively, i.e. Figure 1, 2, 3, etc, and place the captions underneath the figures. Arrange the numbering of tables as Table 1, 2, 3, etc, and place the captions above the tables. Incorporate both figures and tables within the body of the text.</p>
<p>Maximum length of articles should be <strong>six (6)</strong> pages, including the title page, and sized A4 (210mm x 297mm). Every submitted article of six (6) or fewer pages will attract a fee of <strong>$AUD1000</strong>. Each extra page will attract an additional levy of $AUD150. <strong>Australian residents must also add GST of 10%.</strong></p>'''
            },
            'contact': {
                'title': 'Contact Us',
                'content': '''<p>All correspondence should be directed to the WIETE.</p>
<p><strong>World Institute for Engineering and Technology Education (WIETE)</strong></p>
<p>Melbourne, Australia</p>'''
            }
        }
        
        for key, data in default_contents.items():
            if not SiteContent.query.filter_by(key=key).first():
                content = SiteContent(key=key, title=data['title'], content=data['content'])
                db.session.add(content)
        
        db.session.commit()


if __name__ == '__main__':
    init_db()
    app.run(debug=True, port=5000)
