import BaseService from './BaseService.js';
import Forum from '../models/forum/forum.js';
import ForumPermission from '../models/forum/forum_permission.js';
import ForumUserPermission from '../models/forum/forum_user_permission.js';
import UserRight from '../models/community/user_right.js';
import UserRightType from '../models/type/user_right.js';
import { Op } from 'sequelize';
import { sequelize } from '../utils/sequelize.js';
import User from '../models/community/user.js';
import ForumForumPermission from '../models/forum/forum_forum_permission.js';
import Title from '../models/forum/title.js';
import Message from '../models/forum/message.js';
import { notifyAllUsers } from '../utils/socket.js';
 
class ForumService extends BaseService {

    async createForum(hashedUserId, name, permissions) {
        const user = await this.getUserByHashedId(hashedUserId);
        const isAdmin = await this.hasUserRight(user.id, ['mainadmin', 'forum']);
        if (!isAdmin) {
            throw new Error('Access denied: Only admins can create forums.');
        }
        const newForum = await Forum.create({ name });
        if (permissions && permissions.length > 0) { 
            for (const permission of permissions) {
                const forumPermission = await ForumPermission.findOne({
                    where: { name: permission }
                });
                if (forumPermission) {
                    await newForum.addAssociatedPermissions(forumPermission);
                }
            }
        }
        await notifyAllUsers('forumschanged', {});
        return newForum;
    }

    async deleteForum(hashedUserId, forumId) {
        const user = await this.getUserByHashedId(hashedUserId);
        const isAdmin = await this.hasUserRight(user.id, ['mainadmin', 'forum']);
        if (!isAdmin) {
            throw new Error('Access denied: Only admins can delete forums.');
        }
        const forum = await Forum.findByPk(forumId);
        if (!forum) {
            throw new Error('Forum not found.');
        }
        const transaction = await sequelize.transaction();
        try {
            const forumFormRights = await ForumForumPermission.findAll({
                where: { forumId: forumId }
            });
            for (const forumFormRight of forumFormRights) {
                await forumFormRight.destroy({ transaction });
            }
            const forumUserRights = await ForumUserPermission.findAll({
                where: { forumId: forumId }
            });
            for (const forumUserRight of forumUserRights) {
                await forumUserRight.destroy({ transaction });
            }
            await forum.destroy({ transaction });

            await transaction.commit();
            await notifyAllUsers('forumschanged', {});
            return forum;
        } catch (error) {
            await transaction.rollback();
            throw new Error(`Error deleting forum: ${error.message}`);
        }
    }

    async getAllForums(hashedUserId) {
        const user = await this.getUserByHashedId(hashedUserId);
        if (!user) throw new Error('User not found.');
        const forums = await Forum.findAll({
            include: [
                {
                    model: ForumPermission,
                    as: 'associatedPermissions',
                },
                {
                    model: ForumUserPermission,
                    as: 'userPermissions',
                }
            ] 
        });
        const accessibleForums = [];
        for (const forum of forums) {
            const hasAccess = await this.checkForumAccess(forum, user);
            if (hasAccess) {
                accessibleForums.push(forum);
            }
        }
        return accessibleForums;
    }

    async getForum(hashedUserId, forumId, page) {
        const user = await this.getUserByHashedId(hashedUserId);
        if (!user) throw new Error('User not found.');
        const forum = await Forum.findByPk(forumId, {
            include: [
                {
                    model: ForumPermission,
                    as: 'associatedPermissions',
                },
                {
                    model: ForumUserPermission,
                    as: 'userPermissions',
                }
            ]
        });
        const hasAccess = await this.checkForumAccess(forum, user);
        if (!hasAccess) {
            throw new Error('Access denied.');
        }
        const titlesRaw = await Title.findAll({
            where: {
                forumId
            },
            attributes: [
                'id',
                'title',
                'createdBy',
                'forumId',
                'createdAt',
                'updatedAt',
                [sequelize.literal(`(SELECT COUNT(*) FROM forum.message WHERE message.title_id = title.id)`), 'messageCount'],
                [sequelize.literal(`(SELECT MAX("created_at") FROM forum.message WHERE message.title_id = title.id)`), 'lastMessageDate']
            ],
            include: [
                {
                    model: User,
                    as: 'createdByUser',
                    attributes: ['id', 'username', 'hashedId']
                },
                {
                    model: Message,
                    as: 'messages',
                    attributes: [],
                    include: [
                        {
                            model: User,
                            as: 'lastMessageUser',
                            attributes: ['id', 'username']
                        }
                    ]
                }
            ],
            offset: (page - 1) * 25,
            limit: 25,
            order: [
                ['createdAt', 'DESC']
            ],
            group: [
                'title.id',
                'title.created_at',
            ]
        });
        const totalTopics = await Title.count({ where: { forumId } });
        const titles = titlesRaw.map(title => ({
            id: title.dataValues.id,
            title: title.dataValues.title,
            createdBy: title.createdByUser.username,
            createdByHash: title.createdByUser.hashedId,
            createdAt: title.dataValues.createdAt,
            numberOfItems: title.dataValues.messageCount,
            lastMessageDate: title.dataValues.lastMessageDate
        }));
        return {
            name: forum.name,
            titles,
            page,
            totalTopics,
        };
    }

    async createTopic(hashedUserId, forumId, title, content) {
        const user = await this.getUserByHashedId(hashedUserId);
        if (!user) throw new Error('User not found.');
        const forum = await Forum.findByPk(forumId, {
            include: [
                {
                    model: ForumPermission,
                    as: 'associatedPermissions',
                },
                {
                    model: ForumUserPermission,
                    as: 'userPermissions',
                }
            ]
        });
        const hasAccess = await this.checkForumAccess(forum, user);
        if (!hasAccess) {
            throw new Error('Access denied.');
        }
        const newTopic = await Title.create({ title, forumId, createdBy: user.id });
        await Message.create({ titleId: newTopic.id, text: content, createdBy: user.id})
        await notifyAllUsers('topicschanged', { forumId, topic: newTopic });
        return this.getForum(hashedUserId, forumId, 1);
    }

    async getTopic(hashedUserId, topicId) {
        console.log('[ForumService.getTopic] - start');
        const user = await User.findOne({
            where: {
                hashedId: hashedUserId
            }
        });
        if (!user) {
            throw new Error('User not found.');
        }
        const topic = await Title.findByPk(topicId, {
            include: [
                {
                    model: Message,
                    as:'messages',
                    include: [
                        {
                            model: User,
                            as: 'lastMessageUser',
                            attributes: ['hashedId', 'username'],
                            order: [['createdAt', 'ASC']]
                        }
                    ]
                },
                {
                    model: User,
                    as: 'createdByUser',
                    attributes: ['username', 'hashedId']
                },
                {
                    model: Forum,
                    as: 'forum',
                    attributes: ['id', 'name']
                }
            ]
        });
        if (!topic) {
            throw new Error('Topic not found.');
        }
        console.log('[ForumService.getTopic] - check user permissions');
        const hasAccess = await this.checkForumAccess(topic.forum, user);
        if (!hasAccess) {
            throw new Error('Access denied.');
        }
        console.log('[ForumService.getTopic] - return topic');
        return topic;
    }

    async addMessage(hashedUserId, topicId, content) {
        console.log('[ForumService.addMessage] - start');
        const user = await User.findOne({
            where: {
                hashedId: hashedUserId
            }
        });
        if (!user) {
            throw new Error('User not found.');
        }
        const topic = await Title.findByPk(topicId, {
            include: [
                {
                    model: Message,
                    as:'messages',
                    include: [
                        {
                            model: User,
                            as: 'lastMessageUser',
                            attributes: ['hashedId', 'username'],
                            order: [['createdAt', 'ASC']]
                        }
                    ]
                },
                {
                    model: User,
                    as: 'createdByUser',
                    attributes: ['username', 'hashedId']
                },
                {
                    model: Forum,
                    as: 'forum',
                    attributes: ['id', 'name']
                }
            ]
        });
        if (!topic) {
            throw new Error('Topic not found.');
        }
        const hasAccess = await this.checkForumAccess(topic.forum, user);
        if (!hasAccess) {
            throw new Error('Access denied.');
        }
        console.log('[ForumService.addMessage] - create new message');
        await Message.create({ titleId: topicId, text: content, createdBy: user.id });
        await notifyAllUsers('messageschanged', { topicId, message });
        console.log('[ForumService.addMessage] - return topic');
        return this.getTopic(hashedUserId, topicId);
    }

    async checkForumAccess(forum, user) {
        console.log('[ForumService.checkForumAccess] - start');
        const { age } = user;
        console.log('[ForumService.checkForumAccess] - read user permissions');
        const userPermission = await ForumUserPermission.findOne({
            where: {
                userId: user.id,
                forumId: forum.id
            }
        });
        if (userPermission) {
            return true;
        }
        console.log('[ForumService.checkForumAccess] - read forum permissions');
        const forumPermissions = await ForumForumPermission.findAll({
            where: {
                forumId: forum.id
            }
        });
        console.log('[ForumService.checkForumAccess] - filter persmissions');
        for (const permission of forumPermissions) {
            if (permission.permission === 'age' && age >= parseInt(permission.value, 10)) {
                return true;
            }
            if (permission.permission === 'all' || permission.permission === 'user') {
                return true; 
            }
            const userRight = await UserRight.findOne({
                where: {
                    userId: user.id,
                },
                include: {
                    model: UserRightType,
                    as: 'rightType',
                    where: {
                        [Op.or]: [
                            { title: 'mainadmin' },
                            { title: 'forum' }
                        ]   
                        
                    }
                }
            });

            if (userRight) {
                return true;
            }
        }
        console.log('[ForumService.checkForumAccess] - not successful');

        return false;
    }

    async setPermissions(forumId, permissions) {
        if (permissions && Array.isArray(permissions)) {
            for (const permission of permissions) {
                await ForumPermission.create({
                    forumId,
                    permission: permission.type,
                    value: permission.value
                });
            }
        }
    }

    async checkAdminRights(userId) {
        const userRight = await UserRight.findOne({
            where: { userId },
            include: {
                model: UserRightType,
                as: 'rightType',
                where: { title: ['mainadmin', 'forum'] }
            }
        });

        if (!userRight) {
            throw new Error('Unauthorized: Only admins can perform this action.');
        }
    }
}

export default new ForumService();
