import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useRef, useState } from "react";
import { useEditContext, useFieldsEditContext } from "../client/editContext";
import { deleteSuggestedEdit } from "../services/suggestedEditsService";
import { cleanupPendingSuggestedEditOperations } from "../client/operations";
import { formatDate } from "../utils";
import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
import { DiffView } from "./DiffView";
// Import lucide icons (adjust names as needed)
import { Check, Lightbulb, MoreHorizontal, X } from "lucide-react";
import { DeleteIcon } from "../../components/ui/delete-icon";
import { getFeedbackAvatarClassName, useFeedbackAuthor, } from "./feedbackAvatar";
import { Avatar } from "../../components/ui/avatar";
import { Badge } from "../../components/ui/badge";
import { FeedbackCardFrame, getSuggestionContextSegments, } from "./FeedbackCard";
import { FEEDBACK_SIDEBAR_TEXT_CLASS } from "./feedbackSidebarText";
import { hasSuggestionContentChange } from "./suggestionContentChange";
import { markSuggestedEditRemoved } from "./suggestedEditState";
import { selectFeedbackSuggestedEdit } from "./feedbackSelection";
import { applyRejectedSuggestedEditPatch, applySuggestedEditPatch, rejectSuggestedEditAction, replaceSuggestedEditCompletely, } from "./applySuggestedEditActions";
import { getSuggestedEditItemLanguage, getSuggestedEditItemVersion, } from "./suggestionDisplayValue";
import { applySuggestionPatchToValue } from "./suggestionPatch";
export function SuggestedEditComponent({ edit, resolvedAuthorName, children, }) {
    const editContext = useEditContext();
    const fieldsContext = useFieldsEditContext();
    const ref = useRef(null);
    const [item, setItem] = useState(null);
    const [patchPossible, setPatchPossible] = useState(true);
    const [patchWarning, setPatchWarning] = useState("");
    const [status, setStatus] = useState(edit.status);
    const [isApplying, setIsApplying] = useState(false);
    useEffect(() => {
        setStatus(edit.status);
    }, [edit.status]);
    const canApply = status === "pending" && !editContext?.readonly;
    const hasContentChange = hasSuggestionContentChange(edit.oldValue, edit.newValue);
    // Load the full item from the repository.
    useEffect(() => {
        if (editContext?.itemsRepository &&
            edit.itemId &&
            getSuggestedEditItemLanguage(edit) &&
            getSuggestedEditItemVersion(edit) !== undefined) {
            editContext.itemsRepository
                .getItem({
                id: edit.itemId,
                language: getSuggestedEditItemLanguage(edit),
                version: getSuggestedEditItemVersion(edit),
            })
                .then((loadedItem) => {
                setItem(loadedItem);
                // When the item loads, check if the patch is applicable.
                checkAndComputePatch(loadedItem);
            })
                .catch((err) => {
                console.error("Error loading item:", err);
            });
        }
    }, [
        edit.itemId,
        edit.mainItemLanguage,
        edit.mainItemVersion,
        editContext?.itemsRepository,
    ]);
    const isSelected = editContext?.selectedSuggestedEdit?.id === edit.id;
    useEffect(() => {
        if (isSelected && ref.current) {
            ref.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
        }
    }, [isSelected]);
    // When a suggested edit is clicked, update the focused field and select the item.
    function handleSelectSuggestedEdit() {
        selectFeedbackSuggestedEdit(edit, editContext, fieldsContext);
    }
    // Render contextual info by retrieving item and field names from the loaded item.
    const fieldName = item && item.fields
        ? item.fields.find((f) => f.id === edit.fieldId)?.name || undefined
        : undefined;
    const contextSegments = getSuggestionContextSegments(edit, editContext?.currentItemDescriptor?.name, item ? item.name : undefined, fieldName);
    // Allow deletion if the current user owns the suggestion or can administer feedback.
    const canDelete = edit.author === editContext?.user?.name ||
        editContext?.user?.isAdministrator === true;
    const author = useFeedbackAuthor(edit, resolvedAuthorName);
    const deleteCurrentSuggestion = async () => {
        try {
            // Tombstone first so an in-flight debounced save cannot re-create the
            // suggestion after the delete.
            markSuggestedEditRemoved(edit.id);
            const result = await deleteSuggestedEdit(edit);
            if (result.type !== "success") {
                console.warn("Failed to delete suggested edit:", result.summary, result.details);
            }
            cleanupPendingSuggestedEditOperations(edit, editContext?.user);
            if (editContext?.setSuggestedEdits && editContext?.suggestedEdits) {
                const updatedEdits = editContext.suggestedEdits.filter((e) => e.id !== edit.id);
                editContext.setSuggestedEdits(updatedEdits);
            }
            if (editContext?.setComments && editContext?.comments) {
                editContext.setComments(editContext.comments.filter((comment) => comment.suggestedEditId !== edit.id));
            }
            if (editContext?.selectedSuggestedEdit?.id === edit.id) {
                editContext.setSelectedSuggestedEdit(undefined);
            }
        }
        catch (error) {
            console.error("Failed to delete suggested edit:", error);
        }
    };
    const handleDelete = () => {
        editContext?.confirm({
            header: "Delete suggestion",
            message: "Delete this suggestion? This action cannot be undone.",
            acceptLabel: "Delete",
            showCancel: true,
            accept: () => {
                void deleteCurrentSuggestion();
            },
        });
    };
    // Render the header with author info, creation date, and control buttons.
    const renderHeader = () => {
        const showDecisionButtons = canApply && patchPossible && hasContentChange;
        const showApplyAnywayButton = status === "rejected" &&
            !editContext?.readonly &&
            patchPossible &&
            hasContentChange;
        return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Avatar, { src: author.avatarUrl, name: author.displayName, size: "sm", fallbackColor: author.fallbackColor, fallbackClassName: getFeedbackAvatarClassName(edit), className: "!text-[10px] font-medium", title: author.title }), _jsx("div", { className: "min-w-0 flex-1", children: _jsxs("div", { className: "flex min-h-7 min-w-0 items-center gap-2", children: [_jsx("span", { className: "text-neutral-grey-100 truncate text-sm font-medium", title: author.title, children: author.displayName }), _jsx("span", { className: "text-neutral-grey-50 shrink-0 text-xs", children: edit.created ? formatDate(new Date(edit.created)) : "" })] }) }), status === "applied" && (_jsx("span", { className: "text-feedback-green inline-flex h-7 w-7 shrink-0 items-center justify-center", title: edit.updated
                                ? `Applied by ${edit.updatedBy} (${formatDate(new Date(edit.updated))})`
                                : undefined, children: _jsx(Check, { className: "h-4 w-4", strokeWidth: 1 }) })), canDelete && (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 -mr-1 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full", "aria-label": "Suggestion actions", onClick: (e) => e.stopPropagation(), children: _jsx(MoreHorizontal, { className: "h-4 w-4", strokeWidth: 1 }) }) }), _jsx(PopoverContent, { className: `${FEEDBACK_SIDEBAR_TEXT_CLASS} w-44 p-1`, align: "end", children: _jsxs("button", { type: "button", className: "hover:bg-neutral-grey-5 flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-sm", onClick: (e) => {
                                            e.stopPropagation();
                                            handleDelete();
                                        }, children: [_jsx(DeleteIcon, { size: "lg" }), "Delete"] }) })] }))] }), hasContentChange && (_jsxs("div", { className: "border-neutral-grey-10 ml-11 rounded-lg border bg-white p-3 shadow-sm", children: [_jsxs("div", { className: "mb-3 flex min-w-0 items-center justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Lightbulb, { strokeWidth: 1, className: "text-neutral-grey-100 h-4 w-4 shrink-0" }), _jsx("h3", { className: "text-neutral-grey-100 truncate text-sm font-medium", children: "Suggestion" })] }), status === "rejected" && (_jsx(Badge, { variant: "destructive", size: "sm", children: "Rejected" }))] }), _jsxs("div", { className: "text-neutral-grey-100 font-mono text-sm leading-relaxed whitespace-pre-wrap", children: [_jsx(DiffView, { oldText: edit.oldValue, newText: edit.newValue, ignoreFormatting: true, clipUnchanged: true, clipThreshold: 50, clipContext: 10 }), canApply && patchWarning && (_jsxs("div", { className: "text-feedback-red mt-2 font-sans text-xs", children: [patchWarning, _jsx("a", { className: "ml-2 cursor-pointer underline", onClick: handleReplaceCompletely, children: "Click here to replace the field content." })] }))] }), showDecisionButtons && (_jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [_jsxs("button", { type: "button", className: "bg-neutral-grey-10 hover:bg-neutral-grey-5 text-neutral-grey-100 inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md px-3 text-sm font-medium disabled:cursor-not-allowed disabled:opacity-60", onClick: (e) => {
                                        e.stopPropagation();
                                        handleApplyPatch();
                                    }, disabled: isApplying, children: [_jsx(Check, { className: "h-4 w-4", strokeWidth: 1 }), isApplying ? "Applying" : "Apply"] }), _jsxs("button", { type: "button", className: "border-border-default hover:bg-neutral-grey-5 text-neutral-grey-100 inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border bg-white px-3 text-sm font-medium disabled:cursor-not-allowed disabled:opacity-60", onClick: (e) => {
                                        e.stopPropagation();
                                        handleRejectSuggestedEdit();
                                    }, disabled: isApplying, children: [_jsx(X, { className: "h-4 w-4", strokeWidth: 1 }), "Reject"] })] })), showApplyAnywayButton && (_jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: _jsxs("button", { type: "button", className: "bg-neutral-grey-10 hover:bg-neutral-grey-5 text-neutral-grey-100 inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md px-3 text-sm font-medium disabled:cursor-not-allowed disabled:opacity-60", onClick: (e) => {
                                    e.stopPropagation();
                                    handleApplyPatch();
                                }, disabled: isApplying, children: [_jsx(Check, { className: "h-4 w-4", strokeWidth: 1 }), isApplying ? "Applying" : "Apply anyway"] }) }))] })), !hasContentChange && (_jsxs("div", { className: "border-neutral-grey-10 ml-11 rounded-lg border bg-white p-3 shadow-sm", children: [_jsxs("div", { className: "flex min-w-0 items-center justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Lightbulb, { strokeWidth: 1, className: "text-neutral-grey-100 h-4 w-4 shrink-0" }), _jsx("h3", { className: "text-neutral-grey-100 truncate text-sm font-medium", children: "Suggestion" })] }), status === "rejected" && (_jsx(Badge, { variant: "destructive", size: "sm", children: "Rejected" }))] }), _jsx("p", { className: "text-neutral-grey-50 mt-2 text-xs", children: "The suggested text matches the current content; only the comment thread remains." }), canApply && (_jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: _jsxs("button", { type: "button", className: "border-border-default hover:bg-neutral-grey-5 text-neutral-grey-100 inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border bg-white px-3 text-sm font-medium disabled:cursor-not-allowed disabled:opacity-60", onClick: (e) => {
                                    e.stopPropagation();
                                    handleRejectSuggestedEdit();
                                }, disabled: isApplying, children: [_jsx(X, { className: "h-4 w-4", strokeWidth: 1 }), "Reject"] }) }))] }))] }));
    };
    // Helper: Check if the patch is applicable to the current field value.
    async function checkAndComputePatch(loadedItem) {
        const field = loadedItem?.fields?.find((f) => f.id === edit.fieldId);
        if (!field)
            return;
        const currentValue = field.rawValue || "";
        const patchedCandidate = applySuggestionPatchToValue(currentValue, edit.oldValue, edit.newValue);
        if (patchedCandidate === false || typeof patchedCandidate !== "string") {
            setPatchPossible(false);
            setPatchWarning("Patch cannot be applied cleanly to current field value.");
        }
        else {
            setPatchPossible(true);
            setPatchWarning("");
        }
    }
    const runInEditMode = (action, actionDescription) => {
        if (!editContext)
            return;
        if (editContext.mode === "edit") {
            void action();
            return;
        }
        editContext.confirm({
            header: "Switch to Edit Mode?",
            message: `Applying suggestions requires edit mode. Switch to edit mode to ${actionDescription}?`,
            acceptLabel: "Switch and apply",
            rejectLabel: "Cancel",
            accept: async () => {
                await editContext.changeMode("edit", { reason: "apply-suggestion" });
                await action();
            },
        });
    };
    // Handler for applying the patch using editContext.operations.editField.
    async function applySuggestedPatch() {
        if (!patchPossible || isApplying)
            return;
        if (!editContext)
            return;
        setIsApplying(true);
        try {
            const result = status === "rejected"
                ? await applyRejectedSuggestedEditPatch(edit, editContext)
                : await applySuggestedEditPatch(edit, editContext);
            if (result.type === "patch-conflict") {
                setPatchWarning("Patch cannot be applied cleanly to current field value.");
                return;
            }
            if (result.type === "success") {
                setStatus("applied");
                setPatchWarning("");
            }
        }
        finally {
            setIsApplying(false);
        }
    }
    // Handler for replacing the field content completely using editContext.operations.editField.
    async function replaceFieldCompletely() {
        if (!editContext || isApplying)
            return;
        setIsApplying(true);
        try {
            const result = await replaceSuggestedEditCompletely(edit, editContext);
            if (result.type === "success") {
                setStatus("applied");
                setPatchWarning("");
            }
        }
        finally {
            setIsApplying(false);
        }
    }
    async function rejectSuggestedEdit() {
        if (!editContext || isApplying)
            return;
        setIsApplying(true);
        try {
            const result = await rejectSuggestedEditAction(edit, editContext);
            if (result.type === "success") {
                setStatus("rejected");
                setPatchWarning("");
            }
        }
        finally {
            setIsApplying(false);
        }
    }
    function handleApplyPatch() {
        if (!patchPossible || !editContext)
            return;
        runInEditMode(applySuggestedPatch, "apply this suggestion");
    }
    function handleReplaceCompletely() {
        if (!editContext)
            return;
        runInEditMode(replaceFieldCompletely, "replace the field content");
    }
    function handleRejectSuggestedEdit() {
        if (!editContext)
            return;
        void rejectSuggestedEdit();
    }
    return (_jsx("div", { ref: ref, "data-suggestion-id": edit.id, children: _jsxs(FeedbackCardFrame, { contextSegments: contextSegments, selected: !!isSelected, testId: "suggested-edit", className: "cursor-pointer", onClick: handleSelectSuggestedEdit, children: [renderHeader(), children && _jsx("div", { className: "mt-4 pt-3", children: children })] }) }));
}
//# sourceMappingURL=SuggestedEdit.js.map