import DiaryDateActivity from '../models/DiaryDateActivity.js';
import GroupActivity from '../models/GroupActivity.js';
import Group from '../models/Group.js';
import PredefinedActivity from '../models/PredefinedActivity.js';
import { checkAccess } from '../utils/userUtils.js';
import { Op } from 'sequelize';

class DiaryDateActivityService {

    async createActivity(userToken, clubId, data) {
        console.log('[DiaryDateActivityService::createActivity] - check user access');
        await checkAccess(userToken, clubId);
        console.log('[DiaryDateActivityService::createActivity] - add: ', data);
        const { activity, ...restData } = data;
        let predefinedActivity = await PredefinedActivity.findOne({ where: { name: data.activity } });
        if (!predefinedActivity) {
            predefinedActivity = await PredefinedActivity.create({
                name: data.activity,
                description: '',
                duration: data.duration
            });
        }
        restData.predefinedActivityId = predefinedActivity.id;
        const maxOrderId = await DiaryDateActivity.max('orderId', {
            where: { diaryDateId: data.diaryDateId }
        });
        const newOrderId = maxOrderId !== null ? maxOrderId + 1 : 1;
        restData.orderId = newOrderId;
        console.log('[DiaryDateActivityService::createActivity] - create diary date activity');
        return await DiaryDateActivity.create(restData);
    }

    async updateActivity(userToken, clubId, id, data) {
        console.log('[DiaryDateActivityService::updateActivity] - check user access');
        await checkAccess(userToken, clubId);
        console.log('[DiaryDateActivityService::updateActivity] - load activity', id);
        const activity = await DiaryDateActivity.findByPk(id);
        if (!activity) {
            console.log('[DiaryDateActivityService::updateActivity] - activity not found');
            throw new Error('Activity not found');
        }
        console.log('[DiaryDateActivityService::updateActivity] - update activity');
        return await activity.update(data);
    }

    async deleteActivity(userToken, clubId, id) {
        await checkAccess(userToken, clubId);
        const activity = await DiaryDateActivity.findByPk(id);
        if (!activity) {
            throw new Error('Activity not found');
        }
        return await activity.destroy();
    }

    async updateActivityOrder(userToken, clubId, id, newOrderId) {
        console.log(`[DiaryDateActivityService::updateActivityOrder] - Start update for activity id: ${id}`);
        console.log(`[DiaryDateActivityService::updateActivityOrder] - User token: ${userToken}, Club id: ${clubId}, New order id: ${newOrderId}`);
        console.log('[DiaryDateActivityService::updateActivityOrder] - Checking user access');
        await checkAccess(userToken, clubId);
        console.log('[DiaryDateActivityService::updateActivityOrder] - User access confirmed');
        console.log(`[DiaryDateActivityService::updateActivityOrder] - Finding activity with id: ${id}`);
        const activity = await DiaryDateActivity.findByPk(id);
        if (!activity) {
            console.error('[DiaryDateActivityService::updateActivityOrder] - Activity not found, throwing error');
            throw new Error('Activity not found');
        }
        console.log('[DiaryDateActivityService::updateActivityOrder] - Activity found:', activity);
        const currentOrderId = activity.orderId;
        console.log(`[DiaryDateActivityService::updateActivityOrder] - Current order id: ${currentOrderId}`);
        if (newOrderId < currentOrderId) {
            console.log(`[DiaryDateActivityService::updateActivityOrder] - Shifting items down. Moving activities with orderId between ${newOrderId} and ${currentOrderId - 1}`);
            await DiaryDateActivity.increment(
                { orderId: 1 },
                {
                    where: {
                        diaryDateId: activity.diaryDateId,
                        orderId: { [Op.gte]: newOrderId, [Op.lt]: currentOrderId },
                    },
                }
            );
            console.log(`[DiaryDateActivityService::updateActivityOrder] - Items shifted down`);
        } else if (newOrderId > currentOrderId) {
            console.log(`[DiaryDateActivityService::updateActivityOrder] - Shifting items up. Moving activities with orderId between ${currentOrderId + 1} and ${newOrderId}`);
            await DiaryDateActivity.decrement(
                { orderId: 1 },
                {
                    where: {
                        diaryDateId: activity.diaryDateId,
                        orderId: { [Op.lte]: newOrderId, [Op.gt]: currentOrderId },
                    },
                }
            );
            console.log(`[DiaryDateActivityService::updateActivityOrder] - Items shifted up`);
        } else {
            console.log('[DiaryDateActivityService::updateActivityOrder] - New order id is the same as the current order id. No shift required.');
        }
        console.log(`[DiaryDateActivityService::updateActivityOrder] - Setting new order id for activity id: ${id}`);
        activity.orderId = newOrderId;
        console.log('[DiaryDateActivityService::updateActivityOrder] - Saving activity with new order id');
        const savedActivity = await activity.save();
        console.log('[DiaryDateActivityService::updateActivityOrder] - Activity saved:', savedActivity);
        console.log(`[DiaryDateActivityService::updateActivityOrder] - Finished update for activity id: ${id}`);
        return savedActivity;
    }

    async getActivities(userToken, clubId, diaryDateId) {
        console.log('[DiaryDateActivityService::getActivities] - check user access');
        await checkAccess(userToken, clubId);
        console.log(`[DiaryDateActivityService::getActivities] - fetch activities for diaryDateId: ${diaryDateId}`);
        const activities = await DiaryDateActivity.findAll({
            where: { diaryDateId },
            order: [['orderId', 'ASC']],
            include: [
                {
                    model: PredefinedActivity,
                    as: 'predefinedActivity',
                },
                {
                    model: GroupActivity, 
                    as: 'groupActivities',
                    include: [
                        {
                            model: Group,
                            as: 'groupsGroupActivity'
                        },
                        {
                            model: PredefinedActivity,
                            as: 'groupPredefinedActivity',
                        },
                    ],
                }
            ]
        });
        console.log(`[DiaryDateActivityService::getActivities] - found ${activities.length} activities`);
        return activities;
    }

    async addGroupActivity(userToken, clubId, diaryDateId, groupId, activity) {
        console.log('[DiaryDateActivityService::addGroupActivity] Check user access');
        await checkAccess(userToken, clubId);
        console.log('[DiaryDateActivityService::addGroupActivity] Check diary date');
        const diaryDateActivity = await DiaryDateActivity.findOne({
            where: {
                diaryDateId,
                isTimeblock: true,
            },
            order: [['order_id', 'DESC']],
            limit: 1
        });
        if (!diaryDateActivity) {
            console.error('[DiaryDateActivityService::addGroupActivity] Activity not found');
            throw new Error('Activity not found');
        }
        console.log('[DiaryDateActivityService::addGroupActivity] Check group');
        const group = await Group.findByPk(groupId);
        if (!group || group.diaryDateId !== diaryDateActivity.diaryDateId) {
            console.error('[DiaryDateActivityService::addGroupActivity] Group and date don\'t fit');
            throw new Error('Group isn\'t related to date');
        }
        console.log('[DiaryDateActivityService::addGroupActivity] Get predefined activity');
        const [predefinedActivity, created] = await PredefinedActivity.findOrCreate({
            where: {
                name: activity
            }
        });
        console.log('[DiaryDateActivityService::addGroupActivity] Add group activity');
        console.log(predefinedActivity);
        const activityData = {
            diaryDateActivity: diaryDateActivity.id,
            groupId: groupId,
            customActivity: predefinedActivity.id
        }
        console.log(activityData);
        return await GroupActivity.create(activityData);
    }
}

export default new DiaryDateActivityService();
