import { useEffect, useRef, useState } from "react";
import Image from "next/image";
import { CometChatMessageComposer } from "@cometchat/chat-uikit-react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import moment from "moment";
import { useSelector } from "react-redux";
import { useQueryClient } from "@tanstack/react-query";
import { AppStore } from "@/lib/store";
import usePost from "@/Utils/Hooks/usePost";
import { BaseURL, CampaignAPI, CampaignChatAiAPI, CampaignContactNowAPI, ChatAttachmentAPI, ChatPermissionAPI, CommonS3BucketUploadAPI, CommonUploadAPI } from "@/Utils/APIRequest/Endpoints";
import AiIcon from "@/assets/images/ai-icon.png";
import { CustomToast } from "@/Utils/CustomToast";
import { formatNumberWithCommas } from "@/Utils/Other/FormatNumberWithCommas";
import { useTranslation } from "@/Utils/Hooks/useTranslate";
import GradientButton from "../Forms/GradientButton";
import { LoaderSVG } from "../SVGs/CommonSVG";
import {
    clearComposerDraft,
    loadComposerDraft,
    saveComposerDraft,
} from "./composerDraftStorage";

// Re-export for callers that already import from this module
export { flushActiveComposerDraft } from "./composerDraftStorage";

const NOT_MEMBER_CODES = new Set<string | undefined>([
    "ERR_NOT_A_MEMBER_OF_GROUP",
    "ERR_NOT_A_MEMBER",
    "NOT_A_MEMBER_OF_GROUP",
    "ERR_NOT_JOINED",
    "ERR_GROUP_NOT_JOINED",
]);

/** Real conversation messages that can trigger chat-permission (excludes custom offer + action/status). */
const TEXT_OR_MEDIA_TYPES = new Set(["text", "image", "video", "audio", "file", "video_upload"]);

const getMessageType = (msg: any) =>
    msg?.type ?? (typeof msg?.getType === "function" ? msg.getType() : undefined);

const isTextOrMediaMessage = (msg: any) => TEXT_OR_MEDIA_TYPES.has(getMessageType(msg));

const getSenderId = (msg: any) =>
    msg?.sender?.uid ??
    msg?.data?.entities?.sender?.entity?.uid ??
    (typeof msg?.getSender === "function" ? msg.getSender()?.getUid?.() : undefined);

const hasCustomMessage = (messages: any[]) =>
    messages?.some((m) => getMessageType(m) === "custom");

/** Brand already sent a text/media after the first custom offer (action/status ignored). */
const brandAlreadySentTextOrMediaAfterCustom = (messages: any[], brandUserId: string | number | undefined) => {
    if (!brandUserId || !messages?.length) return false;
    const customIdx = messages.findIndex((m) => getMessageType(m) === "custom");
    if (customIdx === -1) return false;
    return messages.slice(customIdx + 1).some((m) => {
        if (!isTextOrMediaMessage(m)) return false;
        return String(getSenderId(m)) === String(brandUserId);
    });
};

const isAlreadyJoined = (e: any) =>
    e?.code === "ERR_ALREADY_JOINED" ||
    e?.code === "ERR_ALREADY_A_MEMBER" ||
    /already/i.test(e?.message || e?.details || "");

/** Safely ensure we are logged in; throw if not (so caller can surface a toast if desired). */
async function ensureLoggedIn() {
    const u = await CometChat.getLoggedinUser();
    if (!u) {
        throw new Error("Not logged in to CometChat");
    }
}

/** (Re)join group defensively. Safe to call often; ignores "already joined". */
async function ensureJoinedGroup(guid: string, type?: string, password = "") {
    if (!guid) return;
    try {
        await CometChat.joinGroup(guid, (type as any) || CometChat.GROUP_TYPE.PUBLIC, password);
    } catch (e: any) {
        if (!isAlreadyJoined(e)) throw e;
    }
}


const DRAFT_PHASE_STATUSES = new Set(['drafting_deliverables', 'draft_available']);
const POST_PHASE_STATUSES = new Set(['posting_deliverables', 'completion_request']);
/** Early contact statuses: chat-permission fires on first text/media after custom offer. */
const EARLY_CHAT_STATUSES = new Set(['uncontacted', 'waiting_for_quotations', 'quotation_available']);

const getComposerInputEl = (root?: ParentNode | null): HTMLElement | null => {
    if (typeof document === 'undefined') return null;
    const scope = root || document;
    return scope.querySelector('.cometchat-message-composer__input') as HTMLElement | null;
};

const setComposerInputText = (text: string, root?: ParentNode | null) => {
    const inputElement = getComposerInputEl(root);
    if (!inputElement) return false;
    inputElement.innerText = text;
    inputElement.dispatchEvent(new Event('input', { bubbles: true }));
    inputElement.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true }));
    return true;
};

const ChatMessageComposer = (props) => {
    const { selectedUser, selectedGroup, setChatMessages, initialMessage, setOpenSideModal, ManagementDetailData, chatMessages, MainListRefetch, uploading, setMediaUploading, setOtherAttachments, isFromCard, setAttachmentChoiceType, registerOpenChatAttachment, translations: translationsProp, onOutboundMessage, hasPlanChatPermission } = props

    const groupGuid = selectedGroup?.guid ? String(selectedGroup.guid) : '';
    const [inputText, setInputText] = useState('');
    const inputElementRef = useRef<any>(null);
    const queryClient = useQueryClient();
    const userDetails: any = useSelector((state: AppStore) => state.userDetailSlice?.userDetails);
    const { translations: translationsHook } = useTranslation();
    const translations = translationsProp || translationsHook;
    const hasSetInitialMessage = useRef(false);
    const hasReassertedMembershipForGroup = useRef<string | null>(null);
    const hasCalledChatPermission = useRef(false);
    const chatMessagesRef = useRef(chatMessages);
    /** Last typed text — used on unmount when the input DOM is already gone */
    const lastTypedRef = useRef('');
    const groupGuidRef = useRef(groupGuid);
    const prevGuidRef = useRef(groupGuid);
    const restoreUntilRef = useRef(0);
    /** Scope DOM queries to THIS composer — messages + sidebar can both be mounted */
    const composerRootRef = useRef<HTMLDivElement | null>(null);
    /** After Contact Now send — never re-inject that predefined text */
    const [ignoreInitialMessage, setIgnoreInitialMessage] = useState(false);
    const [composerEpoch, setComposerEpoch] = useState(0);
    const initialTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
    const ignoreInitialRef = useRef(false);
    groupGuidRef.current = groupGuid;
    ignoreInitialRef.current = ignoreInitialMessage;

    useEffect(() => {
        chatMessagesRef.current = chatMessages;
    }, [chatMessages]);

    // Keep localStorage in sync while typing; on unmount save lastTyped (never wipe with empty DOM)
    useEffect(() => {
        return () => {
            const guid = groupGuidRef.current;
            if (!guid) return;
            const el = getComposerInputEl(composerRootRef.current);
            if (el) {
                saveComposerDraft(guid, el.innerText || '');
            } else if (lastTypedRef.current.trim()) {
                saveComposerDraft(guid, lastTypedRef.current);
            }
            // If DOM is gone and lastTyped is empty, leave existing draft untouched
        };
    }, []);

    // On conversation change: save previous draft + allow Contact Now again
    useEffect(() => {
        const prev = prevGuidRef.current;
        if (prev && prev !== groupGuid && lastTypedRef.current.trim()) {
            saveComposerDraft(prev, lastTypedRef.current);
        }
        if (prev !== groupGuid) {
            hasCalledChatPermission.current = false;
            hasSetInitialMessage.current = false;
            setIgnoreInitialMessage(false);
            ignoreInitialRef.current = false;
            setComposerEpoch(0);
        }
        prevGuidRef.current = groupGuid;
    }, [groupGuid]);

    // Restore Contact Now text or saved draft into the input
    useEffect(() => {
        if (!groupGuid) return;
        // After send, do not put predefined Contact Now text back
        if (ignoreInitialRef.current) return;

        // Contact-now text is shown in the input once — do NOT persist it as a draft
        const draft = initialMessage ? String(initialMessage) : loadComposerDraft(groupGuid);
        lastTypedRef.current = draft;
        setInputText(draft);
        restoreUntilRef.current = Date.now() + 2500;

        if (!draft) return;

        let tries = 0;
        let cancelled = false;
        const tryRestore = () => {
            if (cancelled || ignoreInitialRef.current) return;
            tries += 1;
            const root = composerRootRef.current;
            const el = getComposerInputEl(root);
            if (!el) {
                if (tries < 30) window.setTimeout(tryRestore, 120);
                return;
            }
            if (!(el.innerText || '').trim()) {
                setComposerInputText(draft, root);
                setInputText(draft);
                lastTypedRef.current = draft;
            } else {
                // Composer already has text — keep React/AI button state in sync
                setInputText((el.innerText || '').trim());
                lastTypedRef.current = el.innerText || '';
            }
            if (initialMessage) hasSetInitialMessage.current = true;
        };
        const t = window.setTimeout(tryRestore, 80);
        return () => {
            cancelled = true;
            window.clearTimeout(t);
        };
    }, [groupGuid, initialMessage, composerEpoch]);

    // Seed "already called" from is_chat_allowed / early-status history (never clear true → false here)
    useEffect(() => {
        const influencer = ManagementDetailData?.campaign?.campaignInfluencers?.[0];
        if (influencer?.is_chat_allowed) {
            hasCalledChatPermission.current = true;
            return;
        }
        const status = influencer?.influencer_status || influencer?.status;
        if (EARLY_CHAT_STATUSES.has(status) && brandAlreadySentTextOrMediaAfterCustom(chatMessages, userDetails?.id)) {
            hasCalledChatPermission.current = true;
        }
    }, [
        selectedGroup?.guid,
        chatMessages,
        userDetails?.id,
        ManagementDetailData?.campaign?.campaignInfluencers?.[0]?.is_chat_allowed,
        ManagementDetailData?.campaign?.campaignInfluencers?.[0]?.influencer_status,
        ManagementDetailData?.campaign?.campaignInfluencers?.[0]?.status,
    ]);

    const hasMinimumCharacters = (text) => {
        return text.trim().length >= 2; // Enable after 2 characters
    };

    const persistTypedText = (raw: string) => {
        const text = String(raw ?? '');
        const trimmed = text.trim();
        lastTypedRef.current = text;
        setInputText((prev) => (prev === trimmed ? prev : trimmed));
        if (!groupGuidRef.current) return;
        // Empty events from a sibling composer / remount must not wipe the shared draft.
        // Only persist non-empty text here; clear via clearComposerDraft after send, or
        // unmount cleanup when this composer's own input is empty.
        if (!trimmed) {
            const el = getComposerInputEl(composerRootRef.current);
            const domTrimmed = (el?.innerText || '').trim();
            // User genuinely cleared THIS composer
            if (el && !domTrimmed) {
                saveComposerDraft(groupGuidRef.current, '');
            }
            return;
        }
        saveComposerDraft(groupGuidRef.current, text);
    };

    useEffect(() => {
        const checkInput = () => {
            const inputElement = getComposerInputEl(composerRootRef.current);
            if (!inputElement) return;
            inputElementRef.current = inputElement;
            const text = inputElement.innerText || '';
            // Polling must not persist empty — remount briefly has "" and would wipe the draft
            if (!text.trim()) return;
            persistTypedText(text);
        };

        const interval = setInterval(checkInput, 400);
        return () => clearInterval(interval);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [groupGuid, composerEpoch]);

    useEffect(() => {
        // Contact-now backup fill — cancel on send; never save predefined text into drafts
        if (initialTimeoutRef.current) {
            clearTimeout(initialTimeoutRef.current);
            initialTimeoutRef.current = null;
        }
        if (!selectedGroup || !initialMessage || ignoreInitialMessage || hasSetInitialMessage.current) {
            return;
        }
        initialTimeoutRef.current = setTimeout(() => {
            if (ignoreInitialRef.current || hasSetInitialMessage.current) return;
            if (setComposerInputText(initialMessage, composerRootRef.current)) {
                setInputText(initialMessage);
                lastTypedRef.current = initialMessage;
                hasSetInitialMessage.current = true;
            }
            initialTimeoutRef.current = null;
        }, 500);
        return () => {
            if (initialTimeoutRef.current) {
                clearTimeout(initialTimeoutRef.current);
                initialTimeoutRef.current = null;
            }
        };
    }, [selectedGroup, initialMessage, ignoreInitialMessage]);

    // Patch  API
    const { isPending: ContactLoader, mutate } = usePost(`${CampaignContactNowAPI}/${ManagementDetailData?.campaign?.id}`, null, (response) => {
        if (response?.status == 200 || response?.status == 201) {
            // MainListRefetch();
        }
    }, 'patch');

    // Brand-only: first text/media send after custom (not action/status) → once
    const { mutate: mutateChatPermission } = usePost(`${ChatPermissionAPI}/${ManagementDetailData?.campaign?.campaignInfluencers?.[0]?.id}`, null,
        (response) => {
            if (response?.status == 200 || response?.status == 201) {
                const isChatAllowed = response?.data?.is_chat_allowed;

                if (typeof isChatAllowed !== "boolean") return;

                const slug = ManagementDetailData?.campaign?.slug;
                const influencerId = ManagementDetailData?.influencerDetails?.id;
                const campaignId = ManagementDetailData?.campaign?.id;

                queryClient.setQueryData(
                    [CampaignAPI, slug, influencerId, campaignId],
                    (old: any) => {
                        if (!old) return old;

                        // Query cache stores CustomFetch (axios) response; select uses data.data
                        const detail = old?.data?.data;
                        const influencer = detail?.campaign?.campaignInfluencers?.[0];
                        if (!influencer) return old;

                        return {
                            ...old,
                            data: {
                                ...old.data,
                                data: {
                                    ...detail,
                                    campaign: {
                                        ...detail.campaign,
                                        campaignInfluencers: [
                                            { ...influencer, is_chat_allowed: isChatAllowed },
                                            ...detail.campaign.campaignInfluencers.slice(1),
                                        ],
                                    },
                                },
                            },
                        };
                    }
                );
            }
        },
        "patch"
    );

    const maybeCallChatPermissionOnFirstSend = (sentMessage: any) => {
        if (userDetails?.role !== "brand") return;
        if (hasCalledChatPermission.current) return;
        if (!isTextOrMediaMessage(sentMessage)) return;
        if (ManagementDetailData?.campaign?.campaignInfluencers?.[0]?.is_chat_allowed) return;

        const influencer = ManagementDetailData?.campaign?.campaignInfluencers?.[0];
        if (influencer?.is_chat_allowed) return;

        const status = influencer?.influencer_status || influencer?.status;
        const messages = chatMessagesRef.current || [];
        const isEarlyStatus = EARLY_CHAT_STATUSES.has(status);

        if (isEarlyStatus) {
            // uncontacted / waiting_for_quotations / quotation_available:
            // first text/media after custom (skip action/status)
            if (!hasCustomMessage(messages)) return;
            if (brandAlreadySentTextOrMediaAfterCustom(messages, userDetails?.id)) return;
        } else {
            // Later statuses: only when plan PermissionData.chat_with_influencers is true.
            // First text/media send after that permission (conversation may already exist).
            if (!hasPlanChatPermission) return;
        }

        hasCalledChatPermission.current = true;
        mutateChatPermission();
    };


    // Auto-join group when not a member: run once when chat loads, and once when tab becomes visible again (no window focus to avoid API on every composer click).
    useEffect(() => {
        const guid = selectedGroup?.guid;
        const groupType = selectedGroup?.type;
        if (!guid) {
            hasReassertedMembershipForGroup.current = null;
            return;
        }
        const joinIfNeeded = async () => {
            if (hasReassertedMembershipForGroup.current === guid) return;
            try {
                await ensureLoggedIn();
                await ensureJoinedGroup(guid, groupType);
                hasReassertedMembershipForGroup.current = guid;
            } catch {
                // swallow; we'll re-check pre-send anyway
            }
        };
        // Join automatically once when this chat loads (so non-members get joined)
        joinIfNeeded();
        // When user returns to tab, re-assert membership once per group (no focus listener = no API on every composer focus)
        const onTabVisible = async () => {
            if (document.visibilityState !== "visible" || !guid) return;
            await joinIfNeeded();
        };
        document.addEventListener("visibilitychange", onTabVisible);
        return () => document.removeEventListener("visibilitychange", onTabVisible);
    }, [selectedGroup?.guid, selectedGroup?.type]);

    // On SDK reconnect, re-assert membership for the active group.
    useEffect(() => {
        const key = "composer-conn-listener";
        CometChat.addConnectionListener(
            key,
            new CometChat.ConnectionListener({
                onConnected: async () => {
                    if (selectedGroup?.guid) {
                        try {
                            await ensureJoinedGroup(selectedGroup.guid, selectedGroup?.type);
                        } catch { }
                    }
                },
            })
        );
        return () => {
            CometChat.removeConnectionListener(key);
        };
    }, [selectedGroup?.guid, selectedGroup?.type]);

    const handleSendButtonClick = async (message: CometChat.BaseMessage | any): Promise<void> => {

        if (!selectedGroup?.guid) return;

        // Only run join check once per chat — skip if we already joined this group (avoids Member Joined API on every send)
        if (hasReassertedMembershipForGroup.current !== selectedGroup.guid) {
            try {
                await ensureLoggedIn();
                await ensureJoinedGroup(selectedGroup.guid, selectedGroup?.type);
                hasReassertedMembershipForGroup.current = selectedGroup.guid;
            } catch (e) {
                console.error("Pre-send ensure failed:", e);
                CustomToast("error", "You're offline. Reconnecting…");
            }
        }

        // Build the message to send
        let toSend: any;

        if (initialMessage || isFromCard) {
            const customData = {
                text: message?.text ?? "",
                title: `${translations?.jobOffer}`,
                amount: `${translations?.amount}: $${formatNumberWithCommas(ManagementDetailData?.campaign?.budget_per_influencer)} ${ManagementDetailData?.campaign?.currency}`,
                due: `${translations?.dueOn}: ${moment(ManagementDetailData?.campaign?.posting_end_date).format("DD MMM YYYY")}`,
                link: `${translations?.makeOffer}`,
            };

            toSend = new CometChat.CustomMessage(
                selectedGroup.guid,
                CometChat.RECEIVER_TYPE.GROUP,
                "custom",
                customData
            );
        } else {
            if (message instanceof CometChat.TextMessage) {
                toSend = message;
            } else {
                const text = message?.text ?? "";
                toSend = new CometChat.TextMessage(selectedGroup.guid, text, CometChat.RECEIVER_TYPE.GROUP);
            }
        }

        const attemptSend = () =>
            CometChat.sendMessage(toSend).then((sent: any) => {
                const convId =
                    typeof sent?.getConversationId === "function" ? sent.getConversationId() : sent?.conversationId;
                if (!selectedGroup?.conversationId || convId === selectedGroup?.conversationId) {
                    // maybeCallChatPermissionOnFirstSend(sent);
                    setChatMessages((prev: any[]) => [...prev, sent]);
                    onOutboundMessage?.(sent);
                    // Stop Contact Now re-fill + clear composer/draft after send
                    ignoreInitialRef.current = true;
                    setIgnoreInitialMessage(true);
                    if (initialTimeoutRef.current) {
                        clearTimeout(initialTimeoutRef.current);
                        initialTimeoutRef.current = null;
                    }
                    clearComposerDraft(selectedGroup?.guid);
                    setComposerInputText('', composerRootRef.current);
                    setInputText('');
                    lastTypedRef.current = '';
                    setComposerEpoch((n) => n + 1);

                    if (initialMessage) {
                        // Only patch when sidebar is already open — spreading null creates a
                        // truthy {} and opens CampaignManagementDetail from Messages hub.
                        setOpenSideModal?.((prev: any) =>
                            prev ? { ...prev, initialMessage: undefined } : prev
                        );
                        composerRootRef.current
                            ?.querySelector(".cometchat-message-composer__send-button")
                            ?.classList.remove("cometchat-message-composer__send-button-active");
                    }
                    setOpenSideModal?.((prev: any) => (prev ? { ...prev, isFromCard: false } : prev));
                }
            });

        try {
            await attemptSend();
        } catch (err: any) {
            if (NOT_MEMBER_CODES.has(err?.code) || /not.*member/i.test(err?.message || "")) {
                try {
                    await ensureJoinedGroup(selectedGroup.guid, selectedGroup?.type);
                    await attemptSend();
                } catch (retryErr) {
                    console.error("Retry after re-join failed:", retryErr);
                }
            } else {
                console.error("Message sending failed:", err);
            }
        }

        if ((userDetails?.role == 'brand' && initialMessage) || (userDetails?.role == 'brand' && isFromCard)) {
            let obj: any = {
                chat_id: ManagementDetailData?.campaign?.campaignInfluencers?.[0]?.id,
                influencer_id: ManagementDetailData?.influencerDetails?.id
            }
            mutate(obj);
        }
    }
    const fileInputRef: any = useRef();
    const openFilePickerRef = useRef<() => void>();

    const uploadToS3 = async (file: File, renamed: string) => {
        try {
            // 1️⃣ Call your pre-signed URL API
            const query = new URLSearchParams({
                root: "files",
                type: "campaign",
                fileName: renamed,
                contentType: file.type,
            }).toString();

            const res = await fetch(`${BaseURL}${CommonS3BucketUploadAPI}?${query}`);

            if (!res.ok) throw new Error("Failed to get presigned URL");

            const { url } = await res.json();

            // 2️⃣ Upload file to S3
            await fetch(url, {
                method: "PUT",
                headers: {
                    "Content-Type": file.type,
                },
                body: file,
            });

            const fileUrl = url.split("?")[0];

            // 3️⃣ Return final S3 URL for chat
            return fileUrl;
        } catch (err) {
            console.error("S3 upload failed:", err);
            throw err;
        }
    };

    const handleFileUpload = async (event) => {
        const file = event.target.files[0];

        if (!file) return;

        const imageMaxSize = 10 * 1024 * 1024; // 10 MB in bytes
        const videoMaxSize = 500 * 1024 * 1024; // 500 MB in bytes

        const allowedImageTypes = ["image/jpeg", "image/png", "image/webp", "image/svg+xml", "image/heic", "image/heif"];
        const allowedVideoTypes = ["video/mp4", "video/mov", "video/mkv", "video/quicktime", "video/x-msvideo", "video/x-matroska", "video/webm"];

        // Check file type
        if (![...allowedImageTypes, ...allowedVideoTypes].includes(file.type)) {
            CustomToast("error", translations?.draftMediaValidation);
            return;
        }

        // Check file size
        if (allowedImageTypes.includes(file.type) && file.size > imageMaxSize) {
            CustomToast("error", translations?.draftImageValidation);
            return;
        }

        if (allowedVideoTypes.includes(file.type) && file.size > videoMaxSize) {
            CustomToast("error", translations?.draftVideoValidation);
            return;
        }

        setMediaUploading(true);

        try {
            if (file.type.startsWith("video")) {
                // 🎥 For video → Upload to S3
                const renamed = addTimestampToFileName(file.name);
                const fileUrl = await uploadToS3(file, renamed);

                // Send as CustomMessage with S3 URL
                const customData = {
                    fileUrl,
                    fileName: renamed,
                    fileType: file.type,
                };

                const customMessage: any = new CometChat.CustomMessage(
                    selectedGroup?.guid,
                    CometChat.RECEIVER_TYPE.GROUP,
                    "video_upload",
                    customData
                );

                customMessage.setCategory("custom");

                const sentMessage = await CometChat.sendMessage(customMessage);
                // maybeCallChatPermissionOnFirstSend(sentMessage);
                setChatMessages((prev) => [...prev, sentMessage]);
                onOutboundMessage?.(sentMessage);
                handleFileAttachment(sentMessage);
            } else {
                // 📸 For image, audio, docs → CometChat MediaMessage
                const mediaMessage = new CometChat.MediaMessage(
                    selectedGroup?.guid,
                    file,
                    file.type.startsWith("image")
                        ? CometChat.MESSAGE_TYPE.IMAGE
                        : file.type.startsWith("audio")
                            ? CometChat.MESSAGE_TYPE.AUDIO
                            : CometChat.MESSAGE_TYPE.FILE,
                    CometChat.RECEIVER_TYPE.GROUP
                );

                const sentMessage = await CometChat.sendMessage(mediaMessage);
                // maybeCallChatPermissionOnFirstSend(sentMessage);
                setChatMessages((prev) => [...prev, sentMessage]);
                onOutboundMessage?.(sentMessage);
                handleFileAttachment(sentMessage);
            }
        } catch (err) {
            console.error("File upload/send failed:", err);
        } finally {
            setMediaUploading(false);
        }
    };

    const addTimestampToFileName = (fileName: string) => {
        const safeName = fileName.replace(/\s+/g, "_");
        const timestamp = new Date().toISOString();
        const dotIndex = safeName.lastIndexOf(".");
        if (dotIndex === -1) {
            return `${fileName}_${timestamp}`;
        }
        const name = fileName.substring(0, dotIndex);
        const ext = fileName.substring(dotIndex);
        return `${name}_${timestamp}${ext}`;
    }

    const campaignInfluencer = ManagementDetailData?.campaign?.campaignInfluencers?.[0];
    const influencerStatus = campaignInfluencer?.influencer_status || campaignInfluencer?.status;

    const openAttachmentPicker = () => fileInputRef.current?.click?.();

    const handlePlusButtonClick = (event: Event) => {
        // Always use our file picker (S3 video + MediaMessage) so list preview
        // can update via onOutboundMessage — never CometChat's native attach flow.
        event.preventDefault();
        event.stopImmediatePropagation();

        if (userDetails?.role !== 'influencer' || !setAttachmentChoiceType) {
            openAttachmentPicker();
            return;
        }

        if (DRAFT_PHASE_STATUSES.has(influencerStatus)) {
            setAttachmentChoiceType('draft');
            return;
        }

        if (POST_PHASE_STATUSES.has(influencerStatus)) {
            setAttachmentChoiceType('post');
            return;
        }

        openAttachmentPicker();
    };

    useEffect(() => {
        openFilePickerRef.current = openAttachmentPicker;
        registerOpenChatAttachment?.(openAttachmentPicker);
    }, [registerOpenChatAttachment, selectedGroup]);

    useEffect(() => {
        const root = composerRootRef.current;
        const plusButton = root?.querySelector(
            ".cometchat-message-composer__secondary-button-view-attachment-button"
        );
        if (plusButton) {
            plusButton.addEventListener("click", handlePlusButtonClick, true);
        }
        return () => {
            if (plusButton) {
                plusButton.removeEventListener("click", handlePlusButtonClick, true);
            }
        };
    }, [selectedGroup, influencerStatus, userDetails?.role, setAttachmentChoiceType, composerEpoch]);

    // API Post for AI
    const { isPending: aiPending, mutate: aiMutate } = usePost(CampaignChatAiAPI, null, null, 'post');

    const handleAIGenerate = async () => {
        if (inputElementRef.current && inputElementRef.current.innerText) {
            const originalText = inputElementRef.current.innerText;
            let obj: any = { message: originalText };

            aiMutate(obj, {
                onSuccess: (response) => {
                    if (response?.status === 200 || response?.status === 201) {
                        inputElementRef.current.innerText = response?.data?.data;
                        setInputText(response?.data?.data);
                    }
                },
                onError: (error) => {
                    CustomToast("error", "Failed to generate campaign requirements with AI");
                    console.error("AI generation error:", error);
                }
            });
        }
    };

    const { mutate: mutateUploadFile, isPending: uploadLoader } = usePost(`${ChatAttachmentAPI}/${ManagementDetailData?.campaign?.campaignInfluencers?.[0]?.id}`, null, (response) => {
        if (response?.status === 201 || response?.status === 200) {
            const attachments = response?.data?.attachments || [];
            const chatAttachments = response?.data?.chat_attachment || [];

            // Combine both arrays
            const combinedAttachments = [...attachments, ...chatAttachments];

            // Set combined attachments to state
            setOtherAttachments(combinedAttachments);
        }
    }, 'patch');

    const handleFileAttachment = (data) => {
        if (data?.type == "video_upload") {
            let obj: any = { attachment: { fileName: data?.data?.customData?.fileName, fileType: data?.data?.customData?.fileType, fileUrl: data?.data?.customData?.fileUrl } };
            mutateUploadFile(obj);
        } else {
            let obj: any = { attachment: { fileName: data?.data?.resource, fileType: data?.data?.type, fileUrl: data?.data?.url } };
            mutateUploadFile(obj);
        }
    };

    const restoredDraft =
        !ignoreInitialMessage && initialMessage
            ? String(initialMessage)
            : loadComposerDraft(groupGuid);

    return (
        <>
            <div className="chat-composer-container text-sm" ref={composerRootRef}>
                {!!groupGuid && (
                <CometChatMessageComposer
                    key={`${groupGuid}-${composerEpoch}`}
                    user={selectedUser}
                    group={selectedGroup}
                    initialComposerText={restoredDraft}
                    hideEmojiKeyboardButton={true}
                    hideVoiceRecordingButton={true}
                    onSendButtonClick={handleSendButtonClick}
                    onTextChange={(text: string) => {
                        // CometChat often emits "" on mount — don't wipe a saved draft
                        if (
                            !String(text || '').trim() &&
                            Date.now() < restoreUntilRef.current &&
                            loadComposerDraft(groupGuid)
                        ) {
                            return;
                        }
                        // Empty from background composer / remount: ignore if OUR input still has text
                        if (!String(text || '').trim()) {
                            const el = getComposerInputEl(composerRootRef.current);
                            if (el && (el.innerText || '').trim()) return;
                            if (
                                !el &&
                                (lastTypedRef.current.trim() || loadComposerDraft(groupGuid))
                            ) {
                                return;
                            }
                        }
                        persistTypedText(text);
                    }}
                    hideAttachmentButton={false}
                    auxiliaryButtonView={
                        <GradientButton
                            buttonType="button"
                            btnTitle="Improve politeness and clarity with AI"
                            onClick={handleAIGenerate}
                            // disabled={aiPending || !hasMinimumWords(inputText)}
                            disabled={aiPending || !hasMinimumCharacters(inputText)}
                            customClass="!h-5 !w-5 !min-w-5 !px-0 !py-0 !rounded-full flex items-center justify-center gap-1"
                        >
                            <Image src={AiIcon} width={14} height={14} alt="AI" />
                            {aiPending && <LoaderSVG />}
                        </GradientButton>
                    }
                />
                )}
                <input type="file" accept="image/*,.mp4,.mov,.mkv,audio/*,.pdf,.doc,.docx" disabled={uploading} onChange={handleFileUpload} style={{ display: 'none' }} ref={fileInputRef} />
            </div>
        </>
    );
}

export default ChatMessageComposer;