"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const models_1 = require("./models");
const helpers_1 = __importDefault(require("../../utils/helpers"));
const models_2 = require("../chats/models");
const constants_1 = __importDefault(require("../../utils/constants"));
const services_1 = __importDefault(require("../../utils/services"));
function getEvents(req, res) {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const user = res.locals.user;
            let { limit = '10', page = '1', type, search, categories } = req.query;
            limit = +limit;
            page = +page;
            const skip = (page - 1) * limit;
            const match = {
                endedAt: { $gt: new Date() },
            };
            if (type !== 'mine' && constants_1.default.locationMode && !user.location) {
                return res.json({ events: [], count: 0 });
            }
            if (type !== 'mine' && constants_1.default.locationMode && user.location) {
                match.location = {
                    $geoWithin: {
                        $centerSphere: [
                            user.location.coordinates, // [lng, lat]
                            constants_1.default.locationDistance / constants_1.default.earthRadius // meters → radians
                        ]
                    }
                };
            }
            // search filter
            if (search) {
                match.$or = [
                    { title: { $regex: search, $options: 'i' } },
                    { description: { $regex: search, $options: 'i' } },
                ];
            }
            // category filter
            if (categories) {
                match.category = { $in: categories.split(',').filter((e) => e) };
            }
            // Main aggregation
            const pipeline = [
                { $match: match },
                { $sort: { createdAt: -1 } },
                {
                    $lookup: {
                        from: 'chats',
                        localField: 'chat',
                        foreignField: '_id',
                        as: 'chat',
                    },
                },
                { $unwind: '$chat' },
                {
                    $addFields: {
                        participantIds: '$chat.participants.user',
                    },
                },
            ];
            // Conditional filter for "mine" or "others"
            if (type === 'mine') {
                pipeline.push({
                    $match: {
                        participantIds: user._id,
                    },
                });
            }
            else if (type === 'others') {
                pipeline.push({
                    $match: {
                        participantIds: { $ne: user._id },
                    },
                });
            }
            // Pagination and count
            pipeline.push({
                $facet: {
                    events: [{ $skip: skip }, { $limit: limit }],
                    count: [{ $count: 'total' }],
                },
            });
            pipeline.push({
                $project: {
                    events: 1,
                    count: { $ifNull: [{ $arrayElemAt: ['$count.total', 0] }, 0] },
                },
            });
            const result = yield models_1.Event.aggregate(pipeline);
            const { events, count } = result[0];
            for (const event of events) {
                delete event.participantIds;
                const p = event.chat.participants.find((e) => `${e.user}` === `${user._id}`);
                event.joined = !!p;
                event.chat.areYouAdmin = !!(p === null || p === void 0 ? void 0 : p.isAdmin);
            }
            return res.json({ events, count });
        }
        catch (error) {
            console.error(error);
            return res.status(500).json({ message: 'server error' });
        }
    });
}
function getEvent(req, res) {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const id = req.params.id;
            const event = yield models_1.Event.findById(id)
                .populate({ path: 'user', select: 'name photo username email' });
            if (!event) {
                return res.status(404).json({ message: 'event not found' });
            }
            return res.json({ event });
        }
        catch (error) {
            console.log(error);
            return res.status(500).json({ message: 'server error' });
        }
    });
}
function postEvent(req, res) {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const user = res.locals.user;
            const { title, description, date, time, locationString, latitude, longitude, category } = req.body;
            const cover = req.file;
            const { startedAt, endedAt } = getEventTime(date, time);
            if (startedAt < new Date()) {
                return res.status(403).json({ message: 'date and time combination must produce a future timestamp' });
            }
            const chat = new models_2.Chat({
                creator: user._id,
                isGroup: true,
                name: title,
                allowPublicPost: true,
                tags: [],
                participants: [
                    {
                        user: user._id,
                        isAdmin: true,
                    }
                ],
                category,
            });
            const event = new models_1.Event({
                user: user._id,
                title,
                description,
                date,
                time,
                location: {
                    type: 'Point',
                    coordinates: [+longitude, +latitude]
                },
                locationString,
                chat: chat._id,
                category,
                startedAt,
                endedAt,
            });
            let url = undefined;
            if (cover) {
                url = yield helpers_1.default.uploadFile(cover, `chats/${chat._id}/${cover.filename}`);
                if (!url) {
                    return res.status(500).json({ message: 'unable to upload file' });
                }
            }
            // @ts-ignore
            chat.event = event._id;
            chat.photo = url;
            event.cover = url;
            yield chat.save();
            yield event.save();
            return res.status(201).json({ event, chat });
        }
        catch (error) {
            console.log(error);
            return res.status(500).json({ message: 'server error' });
        }
    });
}
function patchEvent(req, res) {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const user = res.locals.user;
            const id = req.params.id;
            const { title, description, date, time, locationString, latitude, longitude, category } = req.body;
            const cover = req.file;
            let startedAt, endedAt;
            if (date && time) {
                const data = getEventTime(date, time);
                startedAt = data.startedAt;
                endedAt = data.endedAt;
                if (startedAt < new Date()) {
                    return res.status(403).json({ message: 'date and time combination must produce a future timestamp' });
                }
            }
            let location;
            if (latitude && longitude) {
                location = [+longitude, +latitude];
            }
            const event = yield models_1.Event.findById(id).populate('chat');
            if (!event) {
                return res.status(404).json({ message: 'event not found' });
            }
            if (event.endedAt < new Date()) {
                return res.status(403).json({ message: 'event is expired' });
            }
            const chat = event.chat;
            if (!chat) {
                return res.status(404).json({ message: 'event chat not found' });
            }
            const admin = chat.participants.find(e => `${e.user}` === `${user._id}` && e.isAdmin);
            if (!admin) {
                return res.status(403).json({ message: 'only admins can update event' });
            }
            let url = undefined;
            if (cover) {
                url = yield helpers_1.default.uploadFile(cover, `chats/${chat._id}/${cover.filename}`);
                if (!url) {
                    return res.status(500).json({ message: 'unable to upload file' });
                }
                if (event.cover) {
                    yield helpers_1.default.deleteR2File(event.cover);
                }
            }
            event.title = title !== null && title !== void 0 ? title : event.title;
            event.description = description !== null && description !== void 0 ? description : event.description;
            event.date = date !== null && date !== void 0 ? date : event.date;
            event.time = time !== null && time !== void 0 ? time : event.time;
            event.locationString = locationString !== null && locationString !== void 0 ? locationString : event.locationString;
            event.location.coordinates = location !== null && location !== void 0 ? location : event.location.coordinates;
            event.category = category !== null && category !== void 0 ? category : event.category;
            event.cover = url !== null && url !== void 0 ? url : event.cover;
            event.startedAt = startedAt !== null && startedAt !== void 0 ? startedAt : event.startedAt;
            event.endedAt = endedAt !== null && endedAt !== void 0 ? endedAt : event.endedAt;
            yield event.save();
            chat.name = title !== null && title !== void 0 ? title : chat.name;
            chat.photo = url !== null && url !== void 0 ? url : chat.photo;
            yield chat.save();
            return res.json({ cover: url, message: 'event updated successfully' });
        }
        catch (error) {
            console.log(error);
            return res.status(500).json({ message: 'server error' });
        }
    });
}
function getEventTime(date, time) {
    const startedAt = new Date(`${date} ${time}`);
    const endedAt = new Date(startedAt.getTime() + 5 * 60 * 60 * 1000); // 5 hour later
    return { startedAt, endedAt };
}
function postOpenedViewAll(req, res) {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const user = res.locals.user;
            (() => __awaiter(this, void 0, void 0, function* () {
                try {
                    const score = yield services_1.default.getOrCreateTodayScore(user._id);
                    if (!score) {
                        return;
                    }
                    const action = score.social.actions.find(e => e.type === 'open-view-all-events');
                    if (!action || action.completed) {
                        return;
                    }
                    action.value = 1;
                    action.completed = true;
                    yield services_1.default.updateScore(score);
                }
                catch (error) {
                    console.log(error);
                }
            }))();
            return res.json({ message: 'done' });
        }
        catch (error) {
            console.log(error);
            return res.status(500).json({ message: 'server error' });
        }
    });
}
const controllers = {
    getEvents,
    getEvent,
    postEvent,
    patchEvent,
    postOpenedViewAll
};
exports.default = controllers;
