"""
Database models for ScholarPress application.
"""

from datetime import datetime
import uuid
import hashlib
import secrets
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from app import db, login_manager


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))


def generate_tracking_id():
    """Generate a unique tracking ID for submissions."""
    return f"SP-{datetime.now().strftime('%Y%m')}-{secrets.token_hex(4).upper()}"


def generate_secure_token():
    """Generate a secure token for message threads."""
    return secrets.token_urlsafe(32)


# Association table for article tags
article_tags = db.Table('article_tags',
    db.Column('article_id', db.Integer, db.ForeignKey('article.id'), primary_key=True),
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True)
)

# Association table for submission tags
submission_tags = db.Table('submission_tags',
    db.Column('submission_id', db.Integer, db.ForeignKey('submission.id'), primary_key=True),
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True)
)


class User(UserMixin, db.Model):
    """User model for admins and editors."""
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, nullable=False, index=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    name = db.Column(db.String(200))
    password_hash = db.Column(db.String(256), nullable=False)
    role = db.Column(db.String(20), nullable=False, default='editor')  # admin, editor
    is_active = db.Column(db.Boolean, default=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # Relationships
    articles = db.relationship('Article', backref='author', lazy='dynamic')
    
    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)
    
    def is_admin(self):
        return self.role == 'admin'
    
    def is_editor(self):
        return self.role in ['admin', 'editor']
    
    def __repr__(self):
        return f'<User {self.username}>'


class Journal(db.Model):
    """Journal model for organizing articles."""
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200), nullable=False)
    slug = db.Column(db.String(200), unique=True, nullable=False, index=True)
    description = db.Column(db.Text)
    cover_image = db.Column(db.String(500))
    issn = db.Column(db.String(20))
    founded_year = db.Column(db.Integer)
    impact_factor = db.Column(db.String(20))
    frequency = db.Column(db.String(50))
    editor = db.Column(db.String(200))
    is_open_access = db.Column(db.Boolean, default=False)
    is_active = db.Column(db.Boolean, default=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # Relationships
    articles = db.relationship('Article', backref='journal', lazy='dynamic')
    submissions = db.relationship('Submission', backref='journal', lazy='dynamic')
    
    def __repr__(self):
        return f'<Journal {self.name}>'


class Tag(db.Model):
    """Tag model for categorizing articles."""
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True, nullable=False, index=True)
    slug = db.Column(db.String(100), unique=True, nullable=False)
    
    def __repr__(self):
        return f'<Tag {self.name}>'


class Article(db.Model):
    """Article model for published research."""
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(500), nullable=False)
    slug = db.Column(db.String(500), unique=True, nullable=False, index=True)
    abstract = db.Column(db.Text)
    content = db.Column(db.Text)
    authors = db.Column(db.String(1000))  # Comma-separated author names
    doi = db.Column(db.String(100), unique=True)
    pdf_file = db.Column(db.String(500))
    citation_count = db.Column(db.Integer, default=0)
    view_count = db.Column(db.Integer, default=0)
    download_count = db.Column(db.Integer, default=0)
    is_published = db.Column(db.Boolean, default=False)
    is_open_access = db.Column(db.Boolean, default=True)
    published_date = db.Column(db.DateTime)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # Publication details
    keywords = db.Column(db.String(500))
    volume = db.Column(db.String(50))
    issue = db.Column(db.String(50))
    pages = db.Column(db.String(50))
    
    # SEO fields
    meta_title = db.Column(db.String(200))
    meta_description = db.Column(db.String(500))
    meta_keywords = db.Column(db.String(500))
    
    # Foreign keys
    journal_id = db.Column(db.Integer, db.ForeignKey('journal.id'), nullable=False)
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    submission_id = db.Column(db.Integer, db.ForeignKey('submission.id'))
    
    # Relationships
    tags = db.relationship('Tag', secondary=article_tags, lazy='subquery',
                          backref=db.backref('articles', lazy='dynamic'))
    
    def generate_doi(self):
        """Generate a DOI-like identifier."""
        return f"10.1234/sp.{datetime.now().year}.{self.id:06d}"
    
    def get_citation(self):
        """Generate citation text."""
        year = self.published_date.year if self.published_date else datetime.now().year
        return f"{self.authors} ({year}). {self.title}. {self.journal.name}. DOI: {self.doi}"
    
    def __repr__(self):
        return f'<Article {self.title[:50]}>'


class Submission(db.Model):
    """Submission model for user-submitted research."""
    id = db.Column(db.Integer, primary_key=True)
    tracking_id = db.Column(db.String(50), unique=True, nullable=False, index=True)
    title = db.Column(db.String(500), nullable=False)
    abstract = db.Column(db.Text, nullable=False)
    authors = db.Column(db.String(1000), nullable=False)
    contact_email = db.Column(db.String(120), nullable=False, index=True)
    affiliation = db.Column(db.String(500))
    orcid = db.Column(db.String(50))
    file_path = db.Column(db.String(500), nullable=False)
    file_type = db.Column(db.String(10))
    status = db.Column(db.String(50), default='pending')  # pending, under_review, revision_requested, accepted, rejected, published
    admin_notes = db.Column(db.Text)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # Foreign keys
    journal_id = db.Column(db.Integer, db.ForeignKey('journal.id'), nullable=False)
    
    # Relationships
    tags = db.relationship('Tag', secondary=submission_tags, lazy='subquery',
                          backref=db.backref('submissions', lazy='dynamic'))
    article = db.relationship('Article', backref='submission_ref', uselist=False)
    status_updates = db.relationship('SubmissionStatusUpdate', backref='submission', 
                                    lazy='dynamic', order_by='SubmissionStatusUpdate.created_at.desc()')
    
    def __repr__(self):
        return f'<Submission {self.tracking_id}>'


class SubmissionStatusUpdate(db.Model):
    """Track submission status changes."""
    id = db.Column(db.Integer, primary_key=True)
    submission_id = db.Column(db.Integer, db.ForeignKey('submission.id'), nullable=False)
    old_status = db.Column(db.String(50))
    new_status = db.Column(db.String(50), nullable=False)
    notes = db.Column(db.Text)
    updated_by_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    updated_by = db.relationship('User', backref='status_updates')
    
    def __repr__(self):
        return f'<StatusUpdate {self.new_status}>'


class ContactThread(db.Model):
    """Contact message thread model."""
    id = db.Column(db.Integer, primary_key=True)
    secure_token = db.Column(db.String(100), unique=True, nullable=False, index=True)
    name = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(120), nullable=False, index=True)
    subject = db.Column(db.String(500), nullable=False)
    is_closed = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # Relationships
    messages = db.relationship('ContactMessage', backref='thread', lazy='dynamic',
                              order_by='ContactMessage.created_at.asc()')
    
    def __repr__(self):
        return f'<ContactThread {self.subject[:30]}>'


class ContactMessage(db.Model):
    """Individual messages within a contact thread."""
    id = db.Column(db.Integer, primary_key=True)
    thread_id = db.Column(db.Integer, db.ForeignKey('contact_thread.id'), nullable=False)
    message = db.Column(db.Text, nullable=False)
    is_from_user = db.Column(db.Boolean, default=True)  # True if from user, False if from admin/editor
    responder_id = db.Column(db.Integer, db.ForeignKey('user.id'))  # If response from admin/editor
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    responder = db.relationship('User', backref='contact_responses')
    
    def __repr__(self):
        return f'<ContactMessage {self.id}>'


class SiteSettings(db.Model):
    """Site-wide settings for customization."""
    id = db.Column(db.Integer, primary_key=True)
    
    # General settings
    site_name = db.Column(db.String(200), default='ScholarPress')
    site_tagline = db.Column(db.String(500))
    site_description = db.Column(db.Text)
    site_logo = db.Column(db.String(500))
    site_favicon = db.Column(db.String(500))
    contact_email = db.Column(db.String(120))
    
    # Homepage content
    hero_title = db.Column(db.String(500))
    hero_subtitle = db.Column(db.Text)
    hero_image = db.Column(db.String(500))
    hero_cta_text = db.Column(db.String(100), default='Submit Your Research')
    hero_cta_link = db.Column(db.String(500), default='/submit')
    
    # About section
    about_title = db.Column(db.String(200))
    about_content = db.Column(db.Text)
    about_image = db.Column(db.String(500))
    
    # Features section
    feature1_title = db.Column(db.String(200), default='Open Access')
    feature1_description = db.Column(db.Text, default='Making research freely accessible to everyone worldwide.')
    feature1_icon = db.Column(db.String(100), default='fa-unlock-alt')
    
    feature2_title = db.Column(db.String(200), default='Peer Review')
    feature2_description = db.Column(db.Text, default='Rigorous peer review process ensuring quality research.')
    feature2_icon = db.Column(db.String(100), default='fa-users')
    
    feature3_title = db.Column(db.String(200), default='Fast Publication')
    feature3_description = db.Column(db.Text, default='Streamlined publication process for timely dissemination.')
    feature3_icon = db.Column(db.String(100), default='fa-rocket')
    
    # Footer content
    footer_text = db.Column(db.Text)
    social_twitter = db.Column(db.String(200))
    social_linkedin = db.Column(db.String(200))
    social_facebook = db.Column(db.String(200))
    
    # Analytics
    google_analytics_id = db.Column(db.String(50))
    
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    def __repr__(self):
        return f'<SiteSettings {self.site_name}>'


class ContentBlock(db.Model):
    """Customizable content blocks for various pages."""
    id = db.Column(db.Integer, primary_key=True)
    page = db.Column(db.String(100), nullable=False, index=True)  # e.g., 'home', 'about', 'submit'
    block_key = db.Column(db.String(100), nullable=False)  # e.g., 'intro_text', 'sidebar_content'
    title = db.Column(db.String(500))
    content = db.Column(db.Text)
    image = db.Column(db.String(500))
    order = db.Column(db.Integer, default=0)
    is_active = db.Column(db.Boolean, default=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    __table_args__ = (db.UniqueConstraint('page', 'block_key', name='_page_block_uc'),)
    
    def __repr__(self):
        return f'<ContentBlock {self.page}/{self.block_key}>'


class PageImage(db.Model):
    """Images used throughout the site."""
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200), nullable=False)
    filename = db.Column(db.String(500), nullable=False)
    alt_text = db.Column(db.String(500))
    page = db.Column(db.String(100))  # Optional: associate with a specific page
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    def __repr__(self):
        return f'<PageImage {self.name}>'
