import { Injectable } from '@nestjs/common';
import { Types } from 'mongoose';
import { chatTypes as connectionType } from './dto/chat.dto';

@Injectable()
export class ChatAggregations {

    async match(query: any) {
        try {
            return {
                $match: query,
            };
        } catch (error) {
            throw error;
        }
    }

    matchData = async (
        user_id: string,
        groupConnectionIds: Types.ObjectId[],
        type: string,
        connection_type: string
    ) => {
        try {
            const uid = new Types.ObjectId(user_id);

            const conditions: any[] = [
                {
                    $or: [
                        { sent_by: uid },
                        { sent_to: uid },
                        { _id: { $in: groupConnectionIds } },
                    ],
                },
                {
                    connection_type: connection_type
                },
                { connection_deleted_by: { $nin: [uid] } },
            ];

            const typeMap: any = {
                [connectionType.NORMAL]: [
                    { connection_locked_by: { $nin: [uid] } },
                    { connection_archived_by: { $nin: [uid] } },
                ],
                [connectionType.LOCKED]: [
                    { connection_locked_by: { $in: [uid] } },
                    { connection_archived_by: { $nin: [uid] } },
                ],
                [connectionType.ARCHIVE]: [
                    { connection_archived_by: { $in: [uid] } },
                    { connection_locked_by: { $nin: [uid] } },
                ],
            };

            // Add type-specific conditions
            conditions.push(...(typeMap[type] || []));

            return { $match: { $and: conditions } };
        } catch (err) {
            throw err;
        }
    };


    lookup_messages = async (user_id) => {
        try {
            return {
                $lookup: {
                    from: "messages",
                    let: { connection_id: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$connection_id", "$$connection_id"] },
                                        {
                                            $not: {
                                                $in: [new Types.ObjectId(user_id), "$deleted_for"]
                                            }
                                        }
                                    ]

                                }
                            }
                        }
                    ],
                    as: "messages"
                }
            }
        }
        catch (err) {
            throw err;
        }
    }

    count_total_messages = async () => {
        try {
            return {
                $set: {
                    total_messages: { $size: "$messages" }
                }
            };
        } catch (err) {
            throw err;
        }
    }

    setData = async (user_id: string) => {
        try {
            return {
                $set: {
                    other_user_id: {
                        $cond: {
                            if: {
                                $eq: ["$sent_by", new Types.ObjectId(user_id)],
                            },
                            then: "$sent_to",
                            else: "$sent_by",
                        },
                    },
                },
            };
        } catch (err) {
            throw err;
        }
    };

    lookupUser = async () => {
        try {
            return {
                $lookup: {
                    from: "users",
                    let: { other_user_id: "$other_user_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $eq: ["$_id", "$$other_user_id"],
                                },
                            },
                        },
                        {
                            $project: {
                                "profile_pic": 1,
                                "name": 1,
                                "username" : 1,
                                "country_code": 1,
                                "phone_no": 1,
                                "is_online": 1,
                            }
                        }
                    ],
                    as: "fetch_users",
                },
            };
        } catch (err) {
            throw err;
        }
    };

    unwindData = async (value: any) => {
        try {
            return {
                $unwind: {
                    path: value,
                    preserveNullAndEmptyArrays: true
                }
            }
        }
        catch (err) {
            throw err;
        }
    }

    filterUsersByName = async (search: string) => {
        try {

            return {
                $redact: {
                    $cond: {
                        if: {
                            $or: [
                                { $eq: [search, undefined] },
                                { $eq: [search, ""] },
                                {
                                    $regexMatch: {
                                        input: "$fetch_users.name",
                                        regex: search,
                                        options: "i",
                                    },
                                },
                                {
                                    $regexMatch: {
                                        input: "$group_name",
                                        regex: search,
                                        options: "i",
                                    },
                                }
                            ],
                        },
                        then: "$$KEEP",
                        else: "$$PRUNE",
                    },
                },
            };
        } catch (err) {
            throw err;
        }
    };

    lookupUnreadChat = async (sent_to: string) => {
        try {
            return {
                $lookup: {
                    from: "messages",
                    let: { connection_id: "$_id" },  //user_id: sent_to,
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $ne: ["$sent_by", new Types.ObjectId(sent_to)] },
                                        { $eq: ["$connection_id", "$$connection_id"] },
                                        { $ne: ["$message_status", "READ"] },
                                        {
                                            $not: {
                                                $in: [new Types.ObjectId(sent_to), "$deleted_for"]
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    ],
                    as: "unread_chat"
                }
            }
        }
        catch (err) {
            throw err;
        }
    }

    countMessageData = async () => {
        try {
            return {
                $set: {
                    count_message: { $size: "$unread_chat" },
                },
            };
        } catch (err) {
            throw err;
        }
    };

    findOtherUserId = async (_id: string) => {
        try {
            return {
                $set: {
                    other_user_id: {
                        $cond: {
                            if: {
                                $eq: [new Types.ObjectId(_id), "$sent_by"],
                            },
                            then: "$sent_to",
                            else: "$sent_by",
                        },
                    },
                },
            };
        } catch (err) {
            throw err;
        }
    };

    fetchMessages = async (user_id: string) => {
        try {
            return {
                $lookup: {
                    from: "messages",
                    let: { connection_id: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$connection_id", "$$connection_id"] },
                                        { $ne : ["$type", "DISAPPEARING"]},
                                        { $not: { $in: [new Types.ObjectId(user_id), "$deleted_for"] } }
                                    ],
                                },
                            },
                        },
                        {
                            $lookup: {
                                from: "users",
                                let: { sender_id: "$sent_by" },
                                pipeline: [
                                    {
                                        $match: {
                                            $expr: {
                                                $eq: ["$_id", "$$sender_id"],
                                            },
                                        },
                                    }
                                ],
                                as: "user1",
                            },
                        },
                        {
                            $unwind: {
                                path: "$user1",
                                preserveNullAndEmptyArrays: true,
                            },
                        },
                        { $sort: { _id: -1 } },
                        { $limit: 1 },
                    ],
                    as: "fetch_messages",
                },
            };
        } catch (err) {
            throw err;
        }
    }

    setLastMsg = async (_id: string) => {
        try {
            return {
                $set: {
                    get_last_message: {
                        $cond: [
                            { $eq: ["$fetch_messages.message_type", null] },
                            null,
                            {
                                $switch: {
                                    branches: [
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "TEXT"] },
                                            then: "$fetch_messages.message"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "IMAGE"] },
                                            then: "image"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "VOICE_NOTE"] },
                                            then: "Voice note"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "VIDEO"] },
                                            then: "video"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "AUDIO"] },
                                            then: "audio"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "DOCUMENT"] },
                                            then: "document"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "LOCATION"] },
                                            then: "location"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "LIVE_LOCATION"] },
                                            then: "live location"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "GIF"] },
                                            then: "gif"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "STICKER"] },
                                            then: "sticker"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "LINK"] },
                                            then: "link"
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "CALL"] },
                                            then: {
                                                $cond: {
                                                    if: { $eq: ["$fetch_messages.call_data.call_mode", "AUDIO"] },
                                                    then: "Audio call",
                                                    else: "Video call"
                                                }
                                            }
                                        },
                                        {
                                            case: { $eq: ["$fetch_messages.message_type", "MEDIA"] },
                                            then: {
                                                $let: {
                                                    vars: {
                                                        mediaTypes: {
                                                            $setUnion: [
                                                                {
                                                                    $map: {
                                                                        input: "$fetch_messages.media",
                                                                        as: "m",
                                                                        in: "$$m.type"
                                                                    }
                                                                }
                                                            ]
                                                        }
                                                    },
                                                    in: {
                                                        $switch: {
                                                            branches: [
                                                                {
                                                                    case: {
                                                                        $eq: ["$$mediaTypes", ["IMAGE"]]
                                                                    },
                                                                    then: "Image"
                                                                },
                                                                {
                                                                    case: {
                                                                        $eq: ["$$mediaTypes", ["VIDEO"]]
                                                                    },
                                                                    then: "Video"
                                                                },
                                                                {
                                                                    case: {
                                                                        $eq: ["$$mediaTypes", ["AUDIO"]]
                                                                    },
                                                                    then: "Audio"
                                                                },
                                                            ],
                                                            default: "Medias"
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    ],
                                    default: "Unknown"
                                }
                            }
                        ]
                    }
                }
            };
        }
        catch (err) {
            throw err;
        }
    };

    firstMessage = async (user_id: string) => {
        try {
            return {
                $lookup: {
                    from: "messages",
                    let: { connection_id: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$connection_id", "$$connection_id"] },
                                    ],
                                },
                            },
                        },
                        { $limit: 1 },
                    ],
                    as: "first_message",
                },
            };
        } catch (err) {
            throw err;
        }
    }

    setFirstMessage = async (_id: string) => {
        try {
            return {
                $set: {
                    chat_initiated: {
                        $cond: [
                            { $gt: [{ $size: { $ifNull: ["$first_message", []] } }, 0] },
                            true,
                            false
                        ]
                    }
                }
            };
        }
        catch (err) {
            throw err;
        }
    };


    groupData = async () => {
        try {
            return {
                $group: {
                    _id: "$_id",
                    connection_id: { $first: "$_id" },
                    other_user_id: { $first: "$other_user_id" },
                    group_name: { $first: "$group_name" },
                    group_image_url: { $first: "$group_image_url" },
                    user: { $first: "$fetch_users" },
                    message_type: { $first: "$fetch_messages.message_type" },
                    connection_type: { $first: "$fetch_messages.connection_type" },
                    last_message: { $first: "$get_last_message" },
                    chat_initiated: { $first: "$chat_initiated" },
                    last_message_sent_by: { $first: "$fetch_messages.sent_by" },
                    unread_msgs: { $first: "$count_message" },
                    total_messages: { $first: "$total_messages" },
                    updated_at: { $first: "$fetch_messages.created_at" },
                    is_blocked: { $first: "$is_blocked" },
                    is_locked: { $first: "$is_locked" },
                    created_at: { $first: "$fetch_messages.created_at" },
                    type: { $first: '$connection_type' },
                    connection_pinned_by: { $first: "$connection_pinned_by" },
                    isMuted: {
                        $first: {
                            $cond: {
                                if: { $gt: [{ $size: "$mutedConnections" }, 0] },
                                then: true,
                                else: false
                            }
                        }
                    }
                },
            };
        } catch (err) {
            throw err;
        }
    };


    filterWithoutMessage = async (user_id: string) => {
        try {
            return {
                $match: {
                    $expr: {
                        $or: [
                            { $eq: ["$connection_type", "GROUP"] },
                            { $eq: ["$chat_initiated", true] }
                        ]
                    }
                }
            };
        } catch (err) {
            throw err;
        }
    };
    /**
     * Lookup blocked users and set is_blocked field
     * Checks if the other user has blocked the current user
     * Only applies to NORMAL (1-on-1) connections, not GROUP connections
     * @param user_id - Current user ID
     */
    lookupBlockedUsers = async (user_id: string) => {
        try {
            return {
                $lookup: {
                    from: "block-users",
                    let: { 
                        other_user_id: "$other_user_id",
                        connection_type: "$connection_type"
                    },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        // Only check blocks for NORMAL connections, not GROUP
                                        { $eq: ["$$connection_type", "NORMAL"] },
                                        { $eq: ["$blocked_by", new Types.ObjectId(user_id)] },
                                        { $eq: ["$blocked_to", "$$other_user_id"] }
                                    ]
                                }
                            }
                        }
                    ],
                    as: "blocked_users"
                }
            };
        } catch (err) {
            throw err;
        }
    };

    /**
     * Add is_blocked field based on blocked_users lookup
     * Returns true if blocked, false otherwise (including for GROUP connections)
     */
    addBlockedStatus = async () => {
        try {
            return {
                $addFields: {
                    is_blocked: {
                        $cond: {
                            if: { $gt: [{ $size: "$blocked_users" }, 0] },
                            then: true,
                            else: false
                        }
                    }
                }
            };
        } catch (err) {
            throw err;
        }
    };

    /**
     * Add is_locked field based on connection_locked_by array
     * Returns true if current user has locked the connection, false otherwise
     * @param user_id - Current user ID
     */
    addLockedStatus = async (user_id: string) => {
        try {
            return {
                $addFields: {
                    is_locked: {
                        $cond: {
                            if: {
                                $and: [
                                    { $isArray: "$connection_locked_by" },
                                    { $in: [new Types.ObjectId(user_id), "$connection_locked_by"] }
                                ]
                            },
                            then: true,
                            else: false
                        }
                    }
                }
            };
        } catch (err) {
            throw err;
        }
    };

    addPinnedStatus = async (user_id: string) => {
        try {
            return {
                $addFields: {
                    is_pinned: {
                        $cond: {
                            if: {
                                $and: [
                                    { $isArray: "$connection_pinned_by" },
                                    { $in: [new Types.ObjectId(user_id), "$connection_pinned_by"] }
                                ]
                            },
                            then: true,
                            else: false
                        }
                    }
                }
            };
        } catch (err) {
            throw err;
        }
    };

    /**
     * Add is_starred field to check if messages are starred by the current user
     * @param user_id - Current user ID
     */
    addFieldsIsStared = async (user_id: string) => {
        try {
            return {
                $addFields: {
                    is_starred: {
                        $cond: {
                            if: {
                                $and: [
                                    { $isArray: "$starred_by" },
                                    { $in: [new Types.ObjectId(user_id), "$starred_by"] }
                                ]
                            },
                            then: true,
                            else: false
                        }
                    }
                }
            };
        } catch (err) {
            throw err;
        }
    };

    async lookupForCheckMutedConnection(user_id: any) {
        try {
            return {
                $lookup: {
                    from: "connections",
                    let: { user_id: new Types.ObjectId(user_id), conn_id: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $and: [
                                        { $eq: ["$_id", "$$conn_id"] },
                                        {
                                            $in: [
                                                "$$user_id",
                                                {
                                                    $ifNull: [
                                                        {
                                                            $map: {
                                                                input: "$connection_muted_by",
                                                                as: "muted",
                                                                in: "$$muted.user_id"
                                                            }
                                                        },
                                                        [] // Ensure an empty array if `connection_muted_by` is null or missing
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            }
                        }
                    ],
                    as: "mutedConnections"
                }
            };
        } catch (error) {
            throw error;
        }
    }

    removeEmptyDoc = async () => {
        try {
            return {
                $redact: {
                    $cond: {
                        if: {
                            $or: [
                                { $eq: ["$total_messages", 0] },
                                { $eq: ["$last_message", "N"] }
                            ]
                        },
                        then: "$$PRUNE",
                        else: "$$KEEP",
                    },
                },
            };
        } catch (err) {
            throw err;
        }
    };

    async facetData(page: any, limit: any) {
        try {
            page = page != undefined ? page : 0;
            limit = limit != undefined ? limit : 10;
            return {
                $facet: {
                    count: [{ $count: "count" }],
                    data: [
                        { $sort: { is_pinned: -1, updated_at: -1 } },
                        { $skip: page },
                        { $limit: limit },
                    ],
                },
            };
        } catch (err) {
            throw err;
        }
    }

    async lookupSentBy() {
        try {
            return {
                $lookup: {
                    from: "users",
                    let: { sent_by: "$sent_by" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $eq: ["$_id", "$$sent_by"],
                                },
                            },
                        },
                        {
                            $project: {
                                _id: 1,
                                name: 1,
                                image: 1,
                                profile_pic: 1,
                            },
                        },
                    ],
                    as: "sent_by",
                },
            };
        } catch (error) {
            throw error;
        }
    }

    async unwindSentBy() {
        try {
            return {
                $unwind: {
                    path: "$sent_by",
                    preserveNullAndEmptyArrays: true,
                },
            };
        } catch (error) {
            throw error;
        }
    }
    async unwindSentTo() {
        try {
            return {
                $unwind: {
                    path: "$sent_to",
                    preserveNullAndEmptyArrays: true,
                },
            };
        } catch (error) {
            throw error;
        }
    }


    async lookupChatEmoji() {
        try {
            return {
                $lookup: {
                    from: "message-reactions",
                    let: { message_id: "$_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $eq: ["$message_id", "$$message_id"]
                                }
                            }
                        },
                        {
                            $lookup: {
                                from: "users",
                                let: { sent_by: "$user_id" },
                                pipeline: [
                                    {
                                        $match: {
                                            $expr: {
                                                $in: ["$_id", "$$sent_by"]
                                            }
                                        }
                                    },
                                    {
                                        $project: {
                                            _id: 1,
                                            name: 1,
                                            image: 1,
                                            profile_pic: 1
                                        }
                                    }
                                ],
                                as: "user_id"
                            }
                        },
                        {
                            $addFields: {
                                total_users: { $size: "$user_id" }
                            }
                        },
                        {
                            $project: {
                                emoji: 1,
                                users: "$user_id",
                                total_users: 1
                            }
                        }
                    ],
                    as: "message_emoji"
                }
            };
        } catch (error) {
            throw error;
        }
    }

    async unwindReplyTo() {
        try {
            return {
                $unwind: {
                    path: "$reply_to",
                    preserveNullAndEmptyArrays: true,
                },
            };
        } catch (error) {
            throw error;
        }
    }
    async lookupSentTo() {
        try {
            return {
                $lookup: {
                    from: "users",
                    let: { sent_to: "$sent_to" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $eq: ["$_id", "$$sent_to"],
                                },
                            },
                        },
                        {
                            $project: {
                                _id: 1,
                                name: 1,
                                image: 1,
                                profile_pic: 1,
                                is_online: 1,
                            },
                        },
                    ],
                    as: "sent_to",
                },
            };
        } catch (error) {
            throw error;
        }
    }

    async lookupReplyTo() {
        try {
            return {
                $lookup: {
                    from: "messages",
                    let: { reply_to: "$reply_msg_id" },
                    pipeline: [
                        {
                            $match: {
                                $expr: {
                                    $eq: ["$_id", "$$reply_to"],
                                },
                            },
                        },
                        {
                            $lookup: {
                                from: "users",
                                let: { sent_by: "$sent_by" },
                                pipeline: [
                                    {
                                        $match: {
                                            $expr: {
                                                $eq: ["$_id", "$$sent_by"],
                                            },
                                        },
                                    },
                                    {
                                        $project: {
                                            _id: 1,
                                            name: 1,
                                            image: 1,
                                            profile_pic: 1,
                                        },
                                    },
                                ],
                                as: "sent_by",
                            },
                        },
                        {
                            $unwind: {
                                path: "$sent_by",
                                preserveNullAndEmptyArrays: true,
                            }
                        },
                        {
                            $lookup: {
                                from: "users",
                                let: { sent_by: "$sent_to" },
                                pipeline: [
                                    {
                                        $match: {
                                            $expr: {
                                                $eq: ["$_id", "$$sent_by"],
                                            },
                                        },
                                    },
                                    {
                                        $project: {
                                            _id: 1,
                                            name: 1,
                                            image: 1,
                                            profile_pic: 1,
                                        },
                                    },
                                ],
                                as: "sent_to",
                            },
                        },
                        {
                            $unwind: {
                                path: "$sent_to",
                                preserveNullAndEmptyArrays: true,
                            }
                        }
                    ],
                    as: "reply_to",
                },
            };
        } catch (error) {
            throw error;
        }
    }


    async groupDataForMessages(userId: Types.ObjectId) {
        try {
            return {
                $group: {
                    _id: "$_id",
                    connection_id: { $first: "$connection_id" },
                    sent_by: { $first: "$sent_by" },
                    sent_to: { $first: "$sent_to" },
                    type: { $first: "$type" },
                    message_type: { $first: "$message_type" },
                    message: { $first: "$message" },
                    media_url: { $first: "$media_url" },
                    read_by: { $first: "$read_by" },
                    deleted_for: { $first: "$deleted_for" },
                    is_deleted: { $first: "$is_deleted" },
                    is_edited: { $first: "$is_edited" },
                    created_at: { $first: "$created_at" },
                    media: { $first: "$media" },
                    stared_by: { $first: "$stared_by" },
                    call: { $first: "$call" },
                    message_status: { $first: "$message_status" },
                    delivered_at: { $first: "$delivered_at" },
                    read_at: { $first: "$read_at" },
                    reply_to: { $first: "$reply_to" },
                    isStared: { $first: "$is_starred" },
                    duration: { $first: "$duration" },
                    message_id: { $first: '$message_id' },
                    lat: { $first: "$lat" },
                    product_id: { $first: "$product_id" },
                    long: { $first: "$long" },
                    is_live_location_ended: { $first: "$is_live_location_ended" },
                    live_end_at: { $first: "$live_end_at" },
                    message_emoji: { $first: "$message_emoji" },
                    is_message_pin: {
                        $first: {
                            $cond: {
                                if: {
                                    $and: [
                                        { $ne: ["$chat_pinned_by", null] },
                                        { $isArray: "$chat_pinned_by" },
                                        { $gt: [{ $size: "$chat_pinned_by" }, 0] },
                                        {
                                            $gt: [
                                                {
                                                    $size: {
                                                        $filter: {
                                                            input: "$chat_pinned_by",
                                                            as: "item",
                                                            cond: { $eq: ["$$item.user_id", userId] }  // 👈 match your userId here
                                                        }
                                                    }
                                                },
                                                0
                                            ]
                                        }
                                    ]
                                },
                                then: true,
                                else: false
                            }
                        }
                    }
                },
            };
        } catch (error) {
            throw error;
        }
    }

    async facetDataForMessage(skip: number, limit: number) {
        try {
            return {
                $facet: {
                    count: [{ $count: "count" }],
                    data: [
                        // sort: { _id: -1 },
                        { $sort: { _id: -1 } },
                        { $skip: skip },
                        { $limit: limit },
                    ],
                },
            };
        } catch (err) {
            throw err;
        }
    }

    async projectData() {
        try {
            return {
                $project: {
                    count: { $arrayElemAt: ["$count.count", 0] },
                    data: 1,
                },
            };
        } catch (err) {
            throw err;
        }
    }
}

