/**
 * Thread timeline — groups messages, filters by visibility,
 * dispatches to message components. Each message is its own panel.
 * Supports inline edit and delete on user messages.
 */
'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useRef } from 'react';
import { cn, RoleAvatar, PdfIcon, LightbulbIcon, MSG_BG, format_time, format_relative, group_messages, build_ai_lookup, find_doc_check, find_text_doc_checks } from './shared.js';
import { FileBar } from './file_bar.js';
import { TextDocCheck } from './text_doc_check.js';
import { TextExtraction } from './text_extraction.js';
import { Clarification } from './clarification.js';
import { SendBackMessage } from './send_back_message.js';
/** Inline edit/delete icons for a message header */
function MessageActions({ msg, current_user_id, on_edit, on_delete }) {
    // Show on user messages (comment, content) — not on system/AI/status messages
    const is_editable = msg.type === 'comment' || msg.type === 'content';
    if (!is_editable)
        return null;
    const [confirming, set_confirming] = useState(false);
    if (confirming) {
        return (_jsxs("div", { className: "flex items-center gap-1 ml-auto", children: [_jsx("span", { className: "text-[11px] text-[#EF4444]", children: "Delete?" }), _jsx("button", { onClick: on_delete, className: "text-[11px] text-[#EF4444] font-medium hover:underline cursor-pointer", children: "Yes" }), _jsx("button", { onClick: () => set_confirming(false), className: "text-[11px] text-[#94A3B8] hover:underline cursor-pointer", children: "No" })] }));
    }
    return (_jsxs("div", { className: "flex items-center gap-1 ml-auto opacity-0 group-hover/card:opacity-100 transition-opacity", children: [_jsx("button", { onClick: on_edit, className: "p-1 text-[#94A3B8] hover:text-[#2563EB] rounded hover:bg-[#F1F5F9] cursor-pointer", title: "Edit", children: _jsx("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }) }), _jsx("button", { onClick: () => set_confirming(true), className: "p-1 text-[#94A3B8] hover:text-[#EF4444] rounded hover:bg-[#FEF2F2] cursor-pointer", title: "Delete", children: _jsx("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }) })] }));
}
/** Inline editor for a message — edit text, remove/add files via drag-and-drop */
function MessageEditor({ msg, on_save, on_cancel, upload_file }) {
    const [text, set_text] = useState(msg.content_text || '');
    const [items, set_items] = useState(msg.content_items || []);
    const [dragging, set_dragging] = useState(false);
    const [uploading, set_uploading] = useState(false);
    const drag_counter = useRef(0);
    const file_input_ref = useRef(null);
    const remove_file = (content_id) => {
        set_items(prev => prev.filter(i => i.content_id !== content_id));
    };
    const format_size = (bytes) => {
        if (bytes < 1024)
            return `${bytes}B`;
        if (bytes < 1048576)
            return `${Math.round(bytes / 1024)}KB`;
        return `${(bytes / 1048576).toFixed(1)}MB`;
    };
    const add_files = async (file_list) => {
        if (upload_file) {
            set_uploading(true);
            try {
                const uploaded = [];
                for (const file of file_list) {
                    const item = await upload_file(file);
                    uploaded.push(item);
                }
                set_items(prev => [...prev, ...uploaded]);
            }
            catch (err) {
                console.error('[MessageEditor] Upload failed:', err);
            }
            finally {
                set_uploading(false);
            }
        }
        else {
            const new_items = file_list.map(file => ({
                content_id: `ct_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
                type: 'file',
                file: {
                    file_id: `f_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
                    file_name: file.name,
                    file_size: format_size(file.size),
                    mime_type: file.type || 'application/octet-stream',
                },
            }));
            set_items(prev => [...prev, ...new_items]);
        }
    };
    const handle_drag_enter = (e) => { e.preventDefault(); e.stopPropagation(); drag_counter.current++; if (e.dataTransfer.types.includes('Files'))
        set_dragging(true); };
    const handle_drag_leave = (e) => { e.preventDefault(); e.stopPropagation(); drag_counter.current--; if (drag_counter.current === 0)
        set_dragging(false); };
    const handle_drag_over = (e) => { e.preventDefault(); e.stopPropagation(); };
    const handle_drop = (e) => {
        e.preventDefault();
        e.stopPropagation();
        set_dragging(false);
        drag_counter.current = 0;
        const dropped = Array.from(e.dataTransfer.files);
        if (dropped.length > 0)
            void add_files(dropped);
    };
    const handle_file_input = (e) => {
        if (e.target.files && e.target.files.length > 0)
            void add_files(Array.from(e.target.files));
        e.target.value = '';
    };
    const handle_save = () => {
        on_save(text.trim(), items);
    };
    const file_items = items.filter(i => i.type === 'file');
    return (_jsxs("div", { onDragEnter: handle_drag_enter, onDragLeave: handle_drag_leave, onDragOver: handle_drag_over, onDrop: handle_drop, className: cn('relative rounded-md border transition-colors', dragging ? 'border-[#2563EB] border-dashed bg-[#EFF6FF]' : 'border-[#2563EB]'), children: [dragging && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-[#EFF6FF]/80 rounded-md z-10 pointer-events-none", children: _jsxs("div", { className: "text-[13px] text-[#2563EB] font-medium flex items-center gap-2", children: [_jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }), "Drop files to add"] }) })), _jsx("textarea", { value: text, onChange: (e) => set_text(e.target.value), className: "w-full px-3 py-2.5 text-[13px] resize-none focus:outline-none bg-transparent rounded-t-md", rows: Math.max(2, text.split('\n').length), placeholder: "Edit your message...", autoFocus: true }), file_items.length > 0 && (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2 px-3 pb-2 mt-2", children: file_items.map(item => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-1.5 rounded-md border border-[#E2E8F0] bg-white text-[12px]", children: [_jsx(PdfIcon, { className: "w-3.5 h-3.5 text-[#94A3B8] flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate text-[#1E293B]", children: item.file?.file_name || 'File' }), item.file?.file_size !== undefined && (_jsx("span", { className: "text-[10px] text-[#94A3B8]", children: item.file.file_size })), _jsx("button", { type: "button", onClick: () => remove_file(item.content_id), className: "p-0.5 rounded text-[#94A3B8] hover:text-[#EF4444] cursor-pointer", title: "Remove file", children: _jsx("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }, item.content_id))) })), _jsxs("div", { className: "flex items-center gap-2 px-3 pb-2.5", children: [_jsxs("button", { onClick: () => file_input_ref.current?.click(), className: "flex items-center gap-1.5 text-[12px] border border-[#E2E8F0] text-[#64748B] rounded px-2.5 py-1 hover:bg-[#F8FAFC] cursor-pointer", children: [_jsx("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13" }) }), "Attach Files"] }), _jsx("div", { className: "flex-1" }), _jsx("button", { onClick: on_cancel, className: "text-[12px] text-[#94A3B8] px-3 py-1 cursor-pointer", children: "Cancel" }), _jsx("button", { onClick: handle_save, className: "text-[12px] font-medium bg-[#2563EB] text-white px-4 py-1.5 rounded hover:bg-[#1D4ED8] cursor-pointer", children: "Save" })] }), _jsx("input", { ref: file_input_ref, type: "file", multiple: true, onChange: handle_file_input, className: "hidden" })] }));
}
export function ThreadTimeline({ messages, role, current_user_id, on_view_file, on_remove_file, on_accept, on_dismiss, on_send_to_client, on_edit_message, on_delete_message, upload_file, on_send_back_issues, on_submit_decisions, on_update_content_item, task_status, file_statuses, classification_results, validation_results, file_manager, on_replacement_files, view_button_variant, show_info_icon, sent_back_resolved_ids, resolving, available_document_types, on_change_document_type, keep_selections, on_keep_change, on_reply_to_issue }) {
    const groups = group_messages(messages, role);
    const all_messages = messages;
    const ai_lookup = build_ai_lookup(messages);
    const [editing_id, set_editing_id] = useState(null);
    return (_jsx("div", { className: "space-y-3", children: groups.map((group, gi) => {
            const first = group[0];
            // ── Status changes — hidden (noisy, no useful info) ──
            if (first.type === 'status_change')
                return null;
            // ── AI analysis — text extraction (agent only) ──
            if (first.type === 'ai_analysis') {
                if (role === 'agent' && first.ai_analysis) {
                    const text_results = first.ai_analysis.items.filter(item => item.extracted_data && item.extracted_data.length > 0);
                    if (text_results.length > 0) {
                        return (_jsxs("div", { className: cn('rounded-lg border p-4', MSG_BG.system), children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx("div", { className: "w-6 h-6 rounded-full bg-[#EEF2FF] flex items-center justify-center flex-shrink-0", children: _jsx(LightbulbIcon, {}) }), _jsx("span", { className: "text-[13px] font-semibold text-[#334155]", children: "Text Analysis" }), _jsx("span", { className: "text-[11px] text-[#94A3B8]", children: format_relative(first.time) }), _jsx("span", { className: "text-[10px] bg-[#EEF2FF] text-[#6366F1] px-1.5 py-0.5 rounded font-medium", children: "Agent only" })] }), _jsx("div", { className: "space-y-3", children: text_results.map(result => (_jsx(TextExtraction, { result: result, on_accept: on_accept, on_send_to_client: on_send_to_client, on_dismiss: on_dismiss }, result.content_ref))) })] }, gi));
                    }
                }
                return null;
            }
            // ── Doc checks — rendered inline, skip standalone ──
            if (first.type === 'doc_check')
                return null;
            // ── Resolution verdict — rendered INSIDE the SendBackMessage panel, never inline ──
            if (first.type === 'resolution_verdict')
                return null;
            // ── Send-back message ──
            if (first.type === 'send_back' && first.send_back) {
                // Walk the timeline reverse to find the latest resolution_verdict so
                // the panel inside SendBackMessage always reflects the most recent
                // resolver run (per-instance / per-round).
                const latest_resolution = find_latest_resolution_verdict(all_messages);
                // Collect all send_back payloads in the group (consecutive messages
                // with the same source_content_id are merged by group_messages).
                const send_back_data_list = group
                    .filter(m => m.type === 'send_back' && m.send_back)
                    .map(m => m.send_back);
                return (_jsxs("div", { className: cn('rounded-lg border p-4', role === 'client' ? 'bg-[#FFF4E6] border-[#FED7AA]' : MSG_BG.agent), children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(RoleAvatar, { role: "agent", name: first.user_name, size: "sm" }), _jsx("span", { className: "text-[13px] font-semibold text-[#0F172A]", children: first.user_name || 'Agent' }), _jsx("span", { className: "text-[11px] text-[#94A3B8]", children: format_time(first.time) })] }), first.content_text && (_jsx("p", { className: "text-[13px] text-[#334155] mb-3", children: first.content_text })), _jsx(SendBackMessage, { data: send_back_data_list, resolved: task_status === 'completed', resolution: latest_resolution, resolving: !!resolving, on_view_file: on_view_file, source_keep_selected: keep_selections ? (keep_selections[first.send_back.source_content_id] ?? true) : undefined, on_keep_change: on_keep_change, show_keep_checkbox: role === 'agent', on_reply: on_reply_to_issue })] }, gi));
            }
            // ── Message card ──
            const msg = first;
            // When the client is viewing, agent messages take an orange tint to
            // match the rest of the client-mode chrome — saves them from a jarring
            // blue island in an otherwise warm theme.
            const msg_bg = role === 'client' && msg.role === 'agent'
                ? 'bg-[#FFF4E6] border-[#FED7AA]'
                : (MSG_BG[msg.role] || MSG_BG.system);
            const is_editing = editing_id === msg.message_id;
            const text_checks = (msg.type === 'comment' && msg.content_text)
                ? find_text_doc_checks(all_messages, msg.message_id)
                : [];
            return (_jsxs("div", { className: cn('rounded-lg border p-4 group/card', msg_bg), children: [_jsxs("div", { className: "flex items-center gap-2 mb-2.5", children: [_jsx(RoleAvatar, { role: msg.role, name: msg.user_name, size: "sm" }), _jsx("span", { className: "text-[13px] font-semibold text-[#0F172A]", children: msg.user_name }), _jsx("span", { className: "text-[11px] text-[#94A3B8]", children: format_time(msg.time) }), task_status !== 'completed' && (_jsx(MessageActions, { msg: msg, current_user_id: current_user_id, on_edit: () => set_editing_id(msg.message_id), on_delete: () => {
                                    on_delete_message?.(msg.message_id);
                                    set_editing_id(null);
                                } }))] }), is_editing ? (_jsx(MessageEditor, { msg: msg, upload_file: upload_file, on_save: (text, items) => {
                            on_edit_message?.(msg.message_id, {
                                content_text: text || undefined,
                                content_items: items.length > 0 ? items : undefined,
                            });
                            set_editing_id(null);
                        }, on_cancel: () => set_editing_id(null) })) : (_jsxs("div", { children: [msg.reply_to && (_jsx("div", { className: "mb-2 flex items-start gap-2 pl-2 border-l-2 border-[#CBD5E1]", children: _jsxs("div", { className: "min-w-0", children: [msg.reply_to.file_name && (_jsx("span", { className: "text-[11px] font-medium text-[#475569]", children: msg.reply_to.file_name })), msg.reply_to.rule_name && (_jsxs("span", { className: "text-[11px] text-[#94A3B8]", children: [" \u00B7 ", msg.reply_to.rule_name] }))] }) })), msg.content_text && msg.type !== 'clarification' && (_jsx("p", { className: "text-[13px] text-[#334155] leading-relaxed whitespace-pre-wrap", children: msg.content_text })), text_checks.map(tc => (_jsx(TextDocCheck, { doc_check_msg: tc, role: role }, tc.message_id))), msg.content_items && msg.content_items.filter(i => i.type === 'file').length > 0 && (() => {
                                // Sort files so replacement chains appear nested: A → B → C
                                const file_items = msg.content_items.filter(i => i.type === 'file');
                                const sorted = [];
                                const has_parent = new Set(file_items.filter(i => i.replaces_content_id).map(i => i.content_id));
                                // Recursively insert an item and all its replacements
                                const insert_chain = (item) => {
                                    sorted.push(item);
                                    for (const r of file_items) {
                                        if (r.replaces_content_id === item.content_id)
                                            insert_chain(r);
                                    }
                                };
                                // Start from root items (those that don't replace anything)
                                for (const item of file_items) {
                                    if (!has_parent.has(item.content_id) && !item.replaces_content_id)
                                        insert_chain(item);
                                }
                                // Build a lookup for depth calculation
                                const items_by_id = new Map(file_items.map(i => [i.content_id, i]));
                                const get_depth = (it) => {
                                    let depth = 0;
                                    let cur = it;
                                    while (cur.replaces_content_id) {
                                        depth++;
                                        const parent = items_by_id.get(cur.replaces_content_id);
                                        if (!parent)
                                            break;
                                        cur = parent;
                                    }
                                    return depth;
                                };
                                // Two-column grid when none of the files in this message
                                // are part of a replacement chain. Chained replacements
                                // need single-column to keep parent → child indentation
                                // visually clear.
                                const has_replacement_chain = file_items.some(i => i.replaces_content_id || i.replaced_by_content_id);
                                const all_selected = sorted.every(item => keep_selections ? (keep_selections[item.content_id] ?? !item.replaced_by_content_id) : true);
                                return (_jsxs("div", { className: "mt-2", children: [role === 'agent' && on_keep_change && sorted.length >= 2 && (_jsx("div", { className: "flex justify-end px-1 mb-1", children: _jsx("button", { type: "button", onClick: () => {
                                                    const updated = { ...(keep_selections ?? {}) };
                                                    for (const item of sorted)
                                                        updated[item.content_id] = !all_selected;
                                                    on_keep_change(updated);
                                                }, className: "text-[11px] text-[#94A3B8] hover:text-[#64748B] transition-colors cursor-pointer", children: all_selected ? 'unselect all' : 'select all' }) })), _jsx("div", { className: cn(has_replacement_chain ? 'space-y-2' : 'grid grid-cols-1 sm:grid-cols-2 gap-2 items-start'), children: sorted.map(item => {
                                                const dc = find_doc_check(all_messages, item.content_id);
                                                const ai = ai_lookup.get(item.content_id);
                                                // Resolve replacement link names from sibling items
                                                const replaced_by_name = item.replaced_by_content_id
                                                    ? msg.content_items?.find(ci => ci.content_id === item.replaced_by_content_id)?.file?.file_name
                                                    : undefined;
                                                const replaces_name = item.replaces_content_id
                                                    ? msg.content_items?.find(ci => ci.content_id === item.replaces_content_id)?.file?.file_name
                                                    : undefined;
                                                const nesting_depth = get_depth(item);
                                                return (_jsx(FileBar, { item: item, doc_check: dc, ai_result: ai, role: role, on_view: on_view_file, on_remove: on_remove_file, on_accept: on_accept, on_dismiss: on_dismiss, on_send_to_client: on_send_to_client, on_send_back_issues: on_send_back_issues, on_submit_decisions: on_submit_decisions, on_update_content_item: on_update_content_item, pipeline_status: file_statuses?.get(item.content_id)?.status || null, pipeline_rule_count: file_statuses?.get(item.content_id)?.total_rules, pipeline_rule_names: file_statuses?.get(item.content_id)?.rule_names, classification_result: classification_results?.get(item.content_id) || null, validation_rule_results: validation_results?.get(item.content_id) || [], file_manager: file_manager, on_replacement_files: on_replacement_files, replaced_by_name: replaced_by_name, replaces_name: replaces_name, nesting_depth: nesting_depth, view_button_variant: view_button_variant, show_info_icon: show_info_icon, task_resolved: task_status === 'completed', sent_back_resolved: sent_back_resolved_ids?.has(item.content_id), available_document_types: available_document_types, on_change_document_type: on_change_document_type, keep_selected: keep_selections ? (keep_selections[item.content_id] ?? !item.replaced_by_content_id) : undefined, on_keep_change: on_keep_change, show_keep_checkbox: role === 'agent' }, item.content_id));
                                            }) })] }));
                            })(), msg.type === 'clarification' && _jsx(Clarification, { msg: msg, role: role })] }))] }, gi));
        }) }));
}
/** Find the most recent resolution_verdict in a message list. */
function find_latest_resolution_verdict(messages) {
    for (let i = messages.length - 1; i >= 0; i--) {
        const m = messages[i];
        if (m.type === 'resolution_verdict' && m.resolution_verdict) {
            return m.resolution_verdict;
        }
    }
    return null;
}
//# sourceMappingURL=thread_timeline.js.map