# models.py
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import json

db = SQLAlchemy()

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=True)
    phone = db.Column(db.String(20), unique=True, nullable=True)
    password = db.Column(db.String(128), nullable=False)
    role = db.Column(db.String(20), default='student')  # student, teacher, admin
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    avatar = db.Column(db.String(200), nullable=True)

    exams_created = db.relationship('Exam', backref='creator', lazy=True)
    submissions = db.relationship('Submission', backref='user', lazy=True)
    drafts = db.relationship('Draft', backref='user', lazy=True)
    posts = db.relationship('Post', backref='author', lazy=True)
    replies = db.relationship('Reply', backref='author', lazy=True)
    reactions = db.relationship('Reaction', backref='user', lazy=True)
    bookmarks = db.relationship('Bookmark', backref='user', lazy=True)
    notifications = db.relationship('Notification', backref='user', lazy=True)
    contest_registrations = db.relationship('ContestRegistration', backref='user', lazy=True)
    teacher_applications = db.relationship('TeacherApplication', backref='user', lazy=True)
    # exam_bookmarks 关系将由 ExamBookmark 中的 backref 自动创建，此处不再定义


class Exam(db.Model):
    __tablename__ = 'exam'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    subject = db.Column(db.String(50))
    duration = db.Column(db.Integer, default=120)
    total_score = db.Column(db.Integer, default=100)
    status = db.Column(db.String(20), default='available')
    creator_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    _questions = db.Column(db.Text, default='[]')

    submissions = db.relationship('Submission', backref='exam', lazy=True, cascade='all, delete-orphan')
    drafts = db.relationship('Draft', backref='exam', lazy=True, cascade='all, delete-orphan')
    # bookmarked_by 关系将由 ExamBookmark 中的 backref 自动创建，此处不再定义

    def set_questions(self, questions):
        self._questions = json.dumps(questions, ensure_ascii=False)

    def get_questions(self):
        return json.loads(self._questions) if self._questions else []


class Submission(db.Model):
    __tablename__ = 'submission'
    id = db.Column(db.Integer, primary_key=True)
    exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    _answers = db.Column(db.Text, default='{}')
    _question_scores = db.Column(db.Text, default='{}')
    score = db.Column(db.Integer, default=0)
    graded = db.Column(db.Boolean, default=False)
    graded_by = db.Column(db.String(80), default='')
    submitted_at = db.Column(db.DateTime, default=datetime.utcnow)

    def set_answers(self, answers):
        self._answers = json.dumps(answers, ensure_ascii=False)

    def get_answers(self):
        return json.loads(self._answers) if self._answers else {}

    def set_question_scores(self, scores):
        self._question_scores = json.dumps(scores, ensure_ascii=False)

    def get_question_scores(self):
        return json.loads(self._question_scores) if self._question_scores else {}

    @property
    def user_name(self):
        return self.user.name if self.user else ''


class Draft(db.Model):
    __tablename__ = 'draft'
    id = db.Column(db.Integer, primary_key=True)
    exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    _answers = db.Column(db.Text, default='{}')
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    def set_answers(self, answers):
        self._answers = json.dumps(answers, ensure_ascii=False)

    def get_answers(self):
        return json.loads(self._answers) if self._answers else {}


class Contest(db.Model):
    __tablename__ = 'contest'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200), nullable=False)
    organizer = db.Column(db.String(100))
    description = db.Column(db.Text)
    start_date = db.Column(db.String(20))
    end_date = db.Column(db.String(20))
    status = db.Column(db.String(20), default='upcoming')
    participants = db.Column(db.Integer, default=0)
    created_by = db.Column(db.String(50))
    contact = db.Column(db.String(100))
    _past_papers = db.Column(db.Text, default='[]')
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    registrations = db.relationship('ContestRegistration', backref='contest', lazy=True)
    posts = db.relationship('Post', backref='contest', lazy=True)

    def set_past_papers(self, papers):
        self._past_papers = json.dumps(papers, ensure_ascii=False)

    def get_past_papers(self):
        return json.loads(self._past_papers) if self._past_papers else []


class ContestRegistration(db.Model):
    __tablename__ = 'contest_registration'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    contest_id = db.Column(db.Integer, db.ForeignKey('contest.id'), nullable=False)
    registered_at = db.Column(db.DateTime, default=datetime.utcnow)


class ContestMembership(db.Model):
    __tablename__ = 'contest_membership'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    contest_id = db.Column(db.Integer, db.ForeignKey('contest.id'), nullable=False)
    role = db.Column(db.String(20), default='member')
    joined_at = db.Column(db.DateTime, default=datetime.utcnow)


class Post(db.Model):
    __tablename__ = 'post'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    contest_id = db.Column(db.Integer, db.ForeignKey('contest.id'), nullable=True)
    tag = db.Column(db.String(50), default='全部')
    is_official = db.Column(db.Boolean, default=False)
    pinned = db.Column(db.Boolean, default=False)
    likes = db.Column(db.Integer, default=0)
    replies_count = db.Column(db.Integer, default=0)
    views = db.Column(db.Integer, default=0)
    has_poll = 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)

    replies = db.relationship('Reply', backref='post', lazy=True, cascade='all, delete-orphan')
    reactions = db.relationship('Reaction', backref='post', lazy=True, cascade='all, delete-orphan')
    bookmarks = db.relationship('Bookmark', backref='post', lazy=True, cascade='all, delete-orphan')
    poll = db.relationship('Poll', backref='post', uselist=False, cascade='all, delete-orphan')


class Reply(db.Model):
    __tablename__ = 'reply'
    id = db.Column(db.Integer, primary_key=True)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    content = db.Column(db.Text, nullable=False)
    reply_to = db.Column(db.String(80), nullable=True)
    likes = db.Column(db.Integer, default=0)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    reactions = db.relationship('Reaction', backref='reply', lazy=True, cascade='all, delete-orphan')


class Poll(db.Model):
    __tablename__ = 'poll'
    id = db.Column(db.Integer, primary_key=True)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False, unique=True)
    question = db.Column(db.String(200), nullable=False)
    multi = db.Column(db.Boolean, default=False)
    total_votes = db.Column(db.Integer, default=0)
    _options = db.Column(db.Text, default='[]')
    _voters = db.Column(db.Text, default='{}')

    def set_options(self, options):
        self._options = json.dumps(options, ensure_ascii=False)

    def get_options(self):
        return json.loads(self._options) if self._options else []

    def set_voters(self, voters):
        self._voters = json.dumps(voters, ensure_ascii=False)

    def get_voters(self):
        return json.loads(self._voters) if self._voters else {}


class Reaction(db.Model):
    __tablename__ = 'reaction'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=True)
    reply_id = db.Column(db.Integer, db.ForeignKey('reply.id'), nullable=True)
    reaction = db.Column(db.String(20), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


class Bookmark(db.Model):
    __tablename__ = 'bookmark'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


class Notification(db.Model):
    __tablename__ = 'notification'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    type = db.Column(db.String(50))
    content = db.Column(db.String(200))
    from_user = db.Column(db.String(80))
    post_id = db.Column(db.Integer, nullable=True)
    read = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


class EditHistory(db.Model):
    __tablename__ = 'edit_history'
    id = db.Column(db.Integer, primary_key=True)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=True)
    reply_id = db.Column(db.Integer, db.ForeignKey('reply.id'), nullable=True)
    editor_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    old_content = db.Column(db.Text)
    new_content = db.Column(db.Text)
    edited_at = db.Column(db.DateTime, default=datetime.utcnow)


class Report(db.Model):
    __tablename__ = 'report'
    id = db.Column(db.Integer, primary_key=True)
    type = db.Column(db.String(20))
    target_id = db.Column(db.Integer, nullable=False)
    reporter_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    reason = db.Column(db.String(100))
    detail = db.Column(db.Text)
    status = db.Column(db.String(20), default='pending')
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


class TeacherApplication(db.Model):
    __tablename__ = 'teacher_application'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    name = db.Column(db.String(80), nullable=False)
    email = db.Column(db.String(120), nullable=False)
    reason = db.Column(db.Text, nullable=False)
    status = db.Column(db.String(20), default='pending')
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


class Friend(db.Model):
    __tablename__ = 'friend'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    friend_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    status = db.Column(db.String(20), default='pending')
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    user = db.relationship('User', foreign_keys=[user_id], backref=db.backref('friends_initiated', lazy='dynamic'))
    friend = db.relationship('User', foreign_keys=[friend_id], backref=db.backref('friends_received', lazy='dynamic'))


class ExamBookmark(db.Model):
    __tablename__ = 'exam_bookmark'
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    # 使用 backref 自动在 User 和 Exam 上创建 'exam_bookmarks' 和 'bookmarked_by' 属性
    user = db.relationship('User', backref=db.backref('exam_bookmarks', lazy='dynamic', cascade='all, delete-orphan'))
    exam = db.relationship('Exam', backref=db.backref('bookmarked_by', lazy='dynamic', cascade='all, delete-orphan'))

    __table_args__ = (db.UniqueConstraint('user_id', 'exam_id', name='unique_exam_bookmark'),)