from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
import os
from config import UPLOAD_FOLDER
from flask_login import UserMixin

db = SQLAlchemy()

class Favorite(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    paste_id = db.Column(db.Integer, db.ForeignKey('paste.id'), nullable=False)
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)

    user = db.relationship('User', backref=db.backref('favorites', lazy=True))
    paste = db.relationship('Paste', backref=db.backref('favorited_by', lazy=True))

    paste_favorites = db.Table(
    'paste_favorites',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
    db.Column('paste_id', db.Integer, db.ForeignKey('paste.id'), primary_key=True)
    )
class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)
    role = db.Column(db.String(10), nullable=False, default='user')
    storage_used = db.Column(db.BigInteger, nullable=False, default=0)  # En bytes
    storage_limit = db.Column(db.BigInteger, nullable=False, default=1 * 1024**3) 
    theme_preference = db.Column(db.String(10), default="light")  # Guardar "light" o "dark"
    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 has_unlimited_storage(self):
        return self.storage_limit == -1

    def get_storage_limit(self):
        """Devuelve el límite de almacenamiento del usuario."""
        return self.storage_limit

shared_pastes = db.Table(
    'shared_pastes',
    db.Column('paste_id', db.Integer, db.ForeignKey('paste.id'), primary_key=True),
    db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True),
    db.Column('can_edit', db.Boolean, default=False)  # Nuevo campo para indicar permiso de edición
)        

# Tabla intermedia para usuarios con permisos de edición
paste_editors = db.Table(
    'paste_editors',
    db.Column('paste_id', db.Integer, db.ForeignKey('paste.id'), primary_key=True),
    db.Column('user_id', db.Integer, db.ForeignKey('user.id'), primary_key=True)
)

class Paste(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255), nullable=True)
    editable = db.Column(db.Boolean, default=True)
    content_type = db.Column(db.String(50), nullable=False)
    filename = db.Column(db.String(255), nullable=True)
    owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    expires_at = db.Column(db.DateTime, nullable=True)  # Nuevo campo de expiración
    language = db.Column(db.String(50), nullable=True)
    last_edited_at = db.Column(db.DateTime, nullable=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    size = db.Column(db.Integer, nullable=True)
    private = db.Column(db.Boolean, default=False)

    # Relaciones
    editors = db.relationship('User', secondary=paste_editors, backref=db.backref('editable_pastes', lazy='dynamic'))
    owner = db.relationship('User', backref=db.backref('owned_pastes', lazy=True), foreign_keys=[owner_id])
    favorites = db.relationship('User', secondary='paste_favorites', backref=db.backref('favorite_pastes', lazy='dynamic'))
    shared_with = db.relationship('User', secondary=shared_pastes, backref=db.backref('shared_pastes', lazy='dynamic'))

    owner = db.relationship(
        'User',
        backref=db.backref('owned_pastes', lazy=True),
        foreign_keys=[owner_id]
    )
    favorites = db.relationship(
        'User',
        secondary='paste_favorites',
        backref=db.backref('favorite_pastes', lazy='dynamic')
    )
    def is_expired(self):
        """ Verifica si el paste ha expirado. """
        return self.expires_at and datetime.utcnow() > self.expires_at
    def to_dict(self):
        return {
            "id": self.id,
            "content_type": self.content_type,
            "filename": self.filename,
            "owner_id": self.owner_id,
            "created_at": self.created_at.isoformat(),
            "language": self.language,
            "user_id": self.user_id,
            "size": self.file_size 
        }


    def get_size(self):
        file_path = os.path.join(UPLOAD_FOLDER, self.filename)
        try:
            return os.path.getsize(file_path)  # Devuelve el tamaño del archivo
        except FileNotFoundError:
            return 0

    def get_type(self):
        # Determinar el tipo de archivo basado en content_type
        if self.content_type.startswith("video"):
            return "Video"
        elif self.content_type.startswith("audio"):
            return "Audio"
        elif self.content_type.startswith("image"):
            return "Image"
        elif self.content_type in [
            "application/zip", "application/x-tar", "application/gzip",
            "application/x-bzip2", "application/x-7z-compressed", "application/x-rar-compressed"
        ]:
            return "Compressed"
        elif self.content_type == "application/pdf":
            return "PDF"
        elif self.content_type.startswith("text"):
            if self.language:
                return f"Text ({self.language})"
            return "Text"
        else:
            return "Other"

    def get_extension(self):
        from src.constants import LANGUAGE_TO_EXTENSION

        # 1. Si filename tiene extensión, úsala
        if self.filename and '.' in self.filename:
            ext = self.filename.rsplit('.', 1)[-1].lower()
            if len(ext) <= 5:  # filtra hashes falsos
                return ext

        # 2. Si hay lenguaje conocido
        if self.language:
            ext = LANGUAGE_TO_EXTENSION.get(self.language.lower())
            if ext:
                return ext

        # 3. Si se puede deducir por content_type
        if self.content_type:
            if self.content_type == "application/pdf":
                return "pdf"
            elif self.content_type in ["application/zip", "application/x-zip-compressed"]:
                return "zip"
            elif self.content_type.startswith("image/"):
                return self.content_type.split("/")[-1].split('+')[0]
            elif self.content_type.startswith("audio/"):
                return self.content_type.split("/")[-1].split('+')[0]
            elif self.content_type.startswith("video/"):
                return self.content_type.split("/")[-1].split('+')[0]
            elif self.content_type.startswith("text/"):
                return "txt"

        return "bin"



    def has_edit_permission(self, user):
        """
        Verifica si un usuario tiene permiso de edición en este paste.
        """
        # Si el usuario no está autenticado, no puede tener permisos
        if not user.is_authenticated:
            print(f"[DEBUG] Unauthenticated user tried to edit paste {self.id}. Permission denied.")
            return False

        # El dueño del paste siempre tiene permisos
        if user.id == self.owner_id:
            print(f"[DEBUG] User {user.id} is the owner of paste {self.id}. Permission granted.")
            return True

        # Verificar si el usuario tiene permisos en `shared_pastes`
        shared_entry = db.session.query(shared_pastes).filter_by(
            paste_id=self.id,
            user_id=user.id,
            can_edit=True
        ).first()

        if shared_entry:
            print(f"[DEBUG] User {user.id} has edit permissions for paste {self.id}.")
        else:
            print(f"[DEBUG] User {user.id} does NOT have edit permissions for paste {self.id}.")

        return shared_entry is not None

    def can_view(self, user):
        """
        Determina si un usuario puede ver el paste.
        """
        if not self.private:
            return True  # Si no es privado, cualquiera puede verlo

        if user and user.is_authenticated:
            if user.id == self.owner_id or user in self.shared_with:
                return True  # Si el usuario es el dueño o está en la lista de compartidos, puede verlo

        return False  # No es dueño ni compartido, acceso denegado
