from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy import text, Table
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
import uuid

from app import db
from .AnalyticsModel import todays_analytics
import Models

block_table = Table('block', Models.Base.metadata,
                    db.Column('user_id', db.ForeignKey('user.id')),
                    db.Column('blocked_user_id', db.ForeignKey('user.id')))

block_post_table = Table('block_post', Models.Base.metadata,
                         db.Column('user_id', db.ForeignKey('user.id')),
                         db.Column('post_id', db.ForeignKey('post.id')))


class UserModel(Models.Base):
    __tablename__ = 'user'

    id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    email = db.Column(db.String, nullable=False, unique=True)
    username = db.Column(db.String, nullable=False, unique=True)
    display_name = db.Column(db.String, nullable=False)
    password_hash = db.Column(db.String, nullable=False)
    login_id = db.Column(UUID(as_uuid=True), nullable=False, default=uuid.uuid4)
    profile_pic_id = db.Column(db.ForeignKey('image.id', use_alter=True, name="fk_user_profile_pic_id"), nullable=True)
    last_active = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
    theme = db.Column(db.String, nullable=False, default="purple")
    profile_pic = db.relationship(
        "ImageModel",
        single_parent=True,
        foreign_keys=profile_pic_id
    )
    personal_information = db.relationship(
        "PersonalInformationModel",
        cascade="all, delete-orphan",
        uselist=False
    )
    matching_preferences = db.relationship(
        "MatchingPreferencesModel",
        cascade="all, delete-orphan",
        uselist=False
    )
    privacy_settings = db.relationship(
        "PrivacySettingsModel",
        cascade="all, delete-orphan",
        uselist=False
    )
    game_user = db.relationship(
        "GameUserModel",
        cascade="all, delete-orphan",
        uselist=False
    )
    moderation_flags = db.relationship(
        "ModerationFlagsModel",
        cascade="all, delete-orphan",
        uselist=False
    )
    likes = db.relationship(
        "UserModel",
        secondary="likes",
        overlaps="user, likes",
        primaryjoin="UserModel.id==LikeModel.user_id",
        secondaryjoin="UserModel.id==LikeModel.likes_id"
    )
    dislikes = db.relationship(
        "UserModel",
        secondary="dislikes",
        overlaps="user, dislikes",
        primaryjoin="UserModel.id==DislikeModel.user_id",
        secondaryjoin="UserModel.id==DislikeModel.dislikes_id"
    )
    matches = db.relationship(
        "MatchModel",
        cascade="all, delete",
        order_by="MatchModel.date.desc()",
        secondary=Models.matching_table,
        back_populates="users"
    )
    chats = db.relationship(
        "ChatModel",
        cascade="all, delete",
        secondary=Models.chatting_table,
        back_populates="users"
    )
    cards = db.relationship(
        "CardModel",
    )
    devices = db.relationship(
        "DeviceModel",
        cascade="all, delete-orphan",
        back_populates="user"
    )
    blocked_user = db.relationship(
        "UserModel",
        secondary=block_table,
        primaryjoin=id == block_table.c.user_id,
        secondaryjoin=id == block_table.c.blocked_user_id,
    )
    blocked_posts = db.relationship(
        "PostModel",
        secondary=block_post_table
    )

    @property
    def score(self):
        return Models.MediaModel.query. \
            join(Models.MediaLikesModel, Models.MediaLikesModel.media_id == Models.MediaModel.id). \
            filter(Models.MediaModel.submitter == self).count()

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
        db.session.commit()

    def get_matched_users(self):
        matches = []
        for match in self.matches:
            users_of_match = set(match.users)
            users_of_match.remove(self)
            matches.extend(users_of_match)
        return matches

    def common_projects(self, other_user):
        return set(self.personal_information.projects) & set(other_user.personal_information.projects)

    def device_activity(self, device_id, device_name):
        if device_id in [d.device_id for d in self.devices]:
            device = [d for d in self.devices if d.device_id == device_id][0]
            device.last_active = datetime.utcnow()
        else:
            device = Models.DeviceModel.query.filter(Models.DeviceModel.device_id == device_id).first()
            if device:
                db.session.delete(device)
                db.session.commit()
            device = Models.DeviceModel(user=self, device_id=device_id, device_name=device_name)
            db.session.add(device)
        db.session.commit()

    def get_user_card(self):
        for card in self.cards:
            if card.type == "user":
                return card
        return False

    def is_active(self):
        now = datetime.utcnow()
        last_active = self.last_active
        self.last_active = now
        db.session.commit()
        if now.date() > last_active.date():
            todays_analytics().active_user_count += 1
        db.session.commit()

    @staticmethod
    def create(username, display_name, password, email):
        user = UserModel(username=username,
                         display_name=display_name,
                         email=email,
                         password_hash=generate_password_hash(password))
        personal_information = Models.PersonalInformationModel(user=user)
        matching_preferences = Models.MatchingPreferencesModel(user=user)
        privacy_settings = Models.PrivacySettingsModel(user=user)
        game_user = Models.GameUserModel(user=user)
        moderation_flags = Models.ModerationFlagsModel(user=user)
        db.session.add(user)
        user.last_active = datetime.utcnow()
        db.session.add(personal_information)
        db.session.add(matching_preferences)
        db.session.add(privacy_settings)
        db.session.add(game_user)
        db.session.add(moderation_flags)
        db.session.commit()
        return user

    def delete(self):
        for card in self.cards:
            db.session.delete(card)
        for post in Models.get_main_channel().posts:
            if post.author == self:
                post.anonymous = True
                post.author = UserModel.matchinit_user()
                if post.image:
                    post.image.uploader = UserModel.matchinit_user()
        for post in Models.PostModel.query.filter(Models.PostModel.author == self).all():
            post.delete()
        self.profile_pic = None
        for image in Models.ImageModel.query.filter(Models.ImageModel.uploader == self).all():
            db.session.delete(image)
        for media in Models.MediaModel.query.filter(Models.MediaModel.submitter == self).all():
            media.submitter = UserModel.matchinit_user()
        for reaction in Models.ReactionModel.query.filter(Models.ReactionModel.user == self).all():
            reaction.user = UserModel.matchinit_user()
        db.engine.execute(text(f"DELETE FROM likes WHERE user_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM likes WHERE likes_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM dislikes WHERE user_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM dislikes WHERE dislikes_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM join_request WHERE user_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM invites WHERE inviter_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM invites WHERE invitee_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM declare WHERE user_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM leader WHERE user_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM banned WHERE user_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM media_likes WHERE user_id = '{self.id}';"))
        db.engine.execute(text(f"DELETE FROM last_read_message WHERE user_id = '{self.id}'"))
        db.engine.execute(text(f"DELETE FROM block WHERE user_id = '{self.id}'"))
        db.engine.execute(text(f"DELETE FROM block WHERE blocked_user_id = '{self.id}'"))
        db.engine.execute(text(f"DELETE FROM block_post WHERE user_id = '{self.id}'"))
        db.session.delete(self)
        db.session.commit()

    @staticmethod
    def create_matchinit_user():
        user = UserModel.create("matchinit", "matchinit", "fqipnqqwdbqwd#qdwdq214ada", "matchinit_no_email@mail")
        user.moderation_flags.can_match = False
        db.session.commit()
        return user

    @staticmethod
    def matchinit_user():
        quer_user = UserModel.query.filter(UserModel.email == 'matchinit_no_email@mail').first()
        if not quer_user:
            return UserModel.create_matchinit_user()
        else:
            return quer_user
