#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from enum import Enum

db = SQLAlchemy()

# Beziehungstypen für Gedankenverknüpfungen
class RelationType(Enum):
    SUPPORTS = "stützt"
    CONTRADICTS = "widerspricht"
    BUILDS_UPON = "baut auf auf"
    GENERALIZES = "verallgemeinert"
    SPECIFIES = "spezifiziert"
    INSPIRES = "inspiriert"

# Beziehungstabelle für viele-zu-viele Beziehung zwischen MindMapNodes
node_relationship = db.Table('node_relationship',
    db.Column('parent_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True),
    db.Column('child_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True)
)

# Beziehungstabelle für öffentliche Knoten und Gedanken
node_thought_association = db.Table('node_thought_association',
    db.Column('node_id', db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True),
    db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True)
)

# Beziehungstabelle für Benutzer-spezifische Mindmap-Knoten und Gedanken
user_mindmap_thought_association = db.Table('user_mindmap_thought_association',
    db.Column('user_mindmap_id', db.Integer, db.ForeignKey('user_mindmap.id'), primary_key=True),
    db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True)
)

# Beziehungstabelle für Benutzer-Bookmarks von Gedanken
user_thought_bookmark = db.Table('user_thought_bookmark',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
    db.Column('thought_id', db.Integer, db.ForeignKey('thought.id'), primary_key=True),
    db.Column('created_at', db.DateTime, default=datetime.utcnow)
)

class User(UserMixin, db.Model):
    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(128))
    is_admin = db.Column(db.Boolean, default=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    last_login = db.Column(db.DateTime)
    avatar = db.Column(db.String(200))
    bio = db.Column(db.Text)
    
    # Beziehungen
    thoughts = db.relationship('Thought', backref='author', lazy=True)
    comments = db.relationship('Comment', backref='author', lazy=True)
    user_mindmaps = db.relationship('UserMindmap', backref='user', lazy=True)
    mindmap_notes = db.relationship('MindmapNote', backref='user', lazy=True)
    bookmarked_thoughts = db.relationship('Thought', secondary=user_thought_bookmark, 
                                         backref=db.backref('bookmarked_by', 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)

class Category(db.Model):
    """Wissenschaftliche Kategorien für die Gliederung der öffentlichen Mindmap"""
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True, nullable=False)
    description = db.Column(db.Text)
    color_code = db.Column(db.String(7))  # Hex color
    icon = db.Column(db.String(50))
    parent_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=True)
    
    # Beziehungen
    children = db.relationship('Category', backref=db.backref('parent', remote_side=[id]))
    nodes = db.relationship('MindMapNode', backref='category', lazy=True)

class MindMapNode(db.Model):
    """Öffentliche Mindmap-Knoten, die für alle Benutzer sichtbar sind"""
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    color_code = db.Column(db.String(7))
    icon = db.Column(db.String(50))
    is_public = db.Column(db.Boolean, default=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    created_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=True)
    
    # Beziehungen für Baumstruktur (mehrere Eltern möglich)
    parents = db.relationship(
        'MindMapNode', 
        secondary=node_relationship,
        primaryjoin=(node_relationship.c.child_id == id),
        secondaryjoin=(node_relationship.c.parent_id == id),
        backref=db.backref('children', lazy='dynamic'),
        lazy='dynamic'
    )
    
    # Beziehungen zu Gedanken
    thoughts = db.relationship('Thought', 
                              secondary=node_thought_association,
                              backref=db.backref('nodes', lazy='dynamic'))
    
    # Beziehung zum Ersteller
    created_by = db.relationship('User', backref='created_nodes')

class UserMindmap(db.Model):
    """Benutzerspezifische Mindmap, die vom Benutzer personalisierbar ist"""
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    is_private = db.Column(db.Boolean, default=True)
    
    # Beziehungen zu öffentlichen Knoten
    public_nodes = db.relationship('MindMapNode', 
                                  secondary='user_mindmap_node',
                                  backref=db.backref('in_user_mindmaps', lazy='dynamic'))
    
    # Beziehungen zu Gedanken
    thoughts = db.relationship('Thought', 
                              secondary=user_mindmap_thought_association,
                              backref=db.backref('in_user_mindmaps', lazy='dynamic'))
    
    # Notizen zu dieser Mindmap
    notes = db.relationship('MindmapNote', backref='mindmap', lazy=True)

# Beziehungstabelle für benutzerorientierte Mindmaps und öffentliche Knoten
class UserMindmapNode(db.Model):
    """Speichert die Beziehung zwischen Benutzer-Mindmaps und öffentlichen Knoten inkl. Position"""
    user_mindmap_id = db.Column(db.Integer, db.ForeignKey('user_mindmap.id'), primary_key=True)
    node_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), primary_key=True)
    x_position = db.Column(db.Float, default=0)  # Position X auf der Mindmap
    y_position = db.Column(db.Float, default=0)  # Position Y auf der Mindmap
    scale = db.Column(db.Float, default=1.0)     # Größe des Knotens
    added_at = db.Column(db.DateTime, default=datetime.utcnow)

class MindmapNote(db.Model):
    """Private Notizen der Benutzer zu ihrer Mindmap"""
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    mindmap_id = db.Column(db.Integer, db.ForeignKey('user_mindmap.id'), nullable=False)
    node_id = db.Column(db.Integer, db.ForeignKey('mind_map_node.id'), nullable=True)
    thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=True)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    color_code = db.Column(db.String(7), default="#FFF59D")  # Farbe der Notiz

class Thought(db.Model):
    """Gedanken und Inhalte, die in der Mindmap verknüpft werden können"""
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    abstract = db.Column(db.Text)
    keywords = db.Column(db.String(500))
    color_code = db.Column(db.String(7))  # Hex color code
    source_type = db.Column(db.String(50))  # PDF, Markdown, Text etc.
    branch = db.Column(db.String(100), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # Beziehungen
    comments = db.relationship('Comment', backref='thought', lazy=True, cascade="all, delete-orphan")
    ratings = db.relationship('ThoughtRating', backref='thought', lazy=True)
    
    outgoing_relations = db.relationship(
        'ThoughtRelation',
        foreign_keys='ThoughtRelation.source_id',
        backref='source_thought',
        lazy=True
    )
    incoming_relations = db.relationship(
        'ThoughtRelation',
        foreign_keys='ThoughtRelation.target_id',
        backref='target_thought',
        lazy=True
    )
    
    @property
    def average_rating(self):
        if not self.ratings:
            return 0
        return sum(r.relevance_score for r in self.ratings) / len(self.ratings)

class ThoughtRelation(db.Model):
    """Beziehungen zwischen Gedanken"""
    id = db.Column(db.Integer, primary_key=True)
    source_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False)
    target_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False)
    relation_type = db.Column(db.Enum(RelationType), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    created_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    
    # Beziehung zum Ersteller
    created_by = db.relationship('User', backref='created_relations')

class ThoughtRating(db.Model):
    """Bewertungen von Gedanken durch Benutzer"""
    id = db.Column(db.Integer, primary_key=True)
    thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    relevance_score = db.Column(db.Integer, nullable=False)  # 1-5
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    __table_args__ = (
        db.UniqueConstraint('thought_id', 'user_id', name='unique_thought_rating'),
    )
    
    # Beziehung zum Benutzer
    user = db.relationship('User', backref='ratings')

class Comment(db.Model):
    """Kommentare zu Gedanken"""
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text, nullable=False)
    thought_id = db.Column(db.Integer, db.ForeignKey('thought.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    last_modified = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) 