import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState } from "react";
import { SimpleToolbar } from "../ui/SimpleToolbar";
import { SimpleIconButton } from "../ui/SimpleIconButton";
import { Plus, Send, X, Mail, Check, Clock } from "lucide-react";
import { Button } from "../../components/ui/button";
import { Checkbox } from "../../components/ui/checkbox";
import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
import { Input } from "../../components/ui/input";
import { Loader2 } from "lucide-react";
import { cn } from "../../lib/utils";
import { PreconfiguredReviewerSelector } from "./PreconfiguredReviewerSelector";
import { useEditContext } from "../client/editContext";
export function ReviewersPanel({ assignments, onAddReviewer, onRemoveReviewer, onSendInvitations, loading, selectedReviewerId, onSelectReviewer, itemIds = [], language, }) {
    const editContext = useEditContext();
    const isLimitedPreviewUser = editContext?.user?.isLimitedPreviewUser ?? false;
    const currentUserEmail = editContext?.user?.email;
    // For limited preview users, only show their own assignment
    const displayAssignments = isLimitedPreviewUser && currentUserEmail
        ? assignments.filter((a) => a.reviewerEmail.toLowerCase() === currentUserEmail.toLowerCase())
        : assignments;
    const [isAddReviewerOpen, setIsAddReviewerOpen] = useState(false);
    const [selectedAssignments, setSelectedAssignments] = useState(new Set());
    const [newReviewer, setNewReviewer] = useState({
        name: "",
        email: "",
    });
    const [showErrors, setShowErrors] = useState(false);
    const [waiting, setWaiting] = useState(false);
    const [invitationErrors, setInvitationErrors] = useState(new Map());
    const [sendingInvitations, setSendingInvitations] = useState(new Set());
    const isValidEmail = (email) => {
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return emailRegex.test(email);
    };
    const emailAlreadyExists = (email) => {
        return assignments.some((a) => a.reviewerEmail.toLowerCase() === email.toLowerCase());
    };
    const handleAddReviewer = async () => {
        setShowErrors(true);
        if (!newReviewer.name || !newReviewer.email) {
            return;
        }
        if (!isValidEmail(newReviewer.email)) {
            return;
        }
        if (emailAlreadyExists(newReviewer.email)) {
            return;
        }
        setWaiting(true);
        await onAddReviewer([newReviewer]);
        setNewReviewer({ name: "", email: "" });
        setIsAddReviewerOpen(false);
        setShowErrors(false);
        setWaiting(false);
    };
    const handleSendInvitations = async () => {
        if (selectedAssignments.size === 0)
            return;
        const assignmentIds = Array.from(selectedAssignments);
        setSendingInvitations(new Set(assignmentIds));
        setInvitationErrors(new Map());
        try {
            await onSendInvitations(assignmentIds);
            setSelectedAssignments(new Set());
        }
        catch (err) {
            const errorMap = new Map();
            // Check if there are individual assignment errors
            if (err && typeof err === "object" && "assignmentErrors" in err) {
                const assignmentErrorMap = err.assignmentErrors;
                if (assignmentErrorMap) {
                    // Use individual errors for each assignment
                    assignmentIds.forEach((id) => {
                        if (assignmentErrorMap.has(id)) {
                            let errorMsg = assignmentErrorMap.get(id);
                            // Ensure error message is a string, not JSON
                            if (typeof errorMsg !== "string") {
                                errorMsg = String(errorMsg);
                            }
                            errorMap.set(id, errorMsg);
                        }
                    });
                }
            }
            // If no individual errors, use the general error message for all
            if (errorMap.size === 0) {
                let errorMessage = err instanceof Error ? err.message : "Failed to send invitations";
                // Ensure error message is a string, not JSON
                if (typeof errorMessage !== "string") {
                    errorMessage = String(errorMessage);
                }
                assignmentIds.forEach((id) => {
                    errorMap.set(id, errorMessage);
                });
            }
            setInvitationErrors(errorMap);
        }
        finally {
            setSendingInvitations(new Set());
        }
    };
    const getReviewerStatus = (assignment) => {
        // Count unique items that have decisions (by itemId + itemLanguage)
        const uniqueItemsWithDecisions = new Set(assignment.decisions?.map((d) => `${d.itemId}:${d.itemLanguage}`) || []);
        const decisionsCount = uniqueItemsWithDecisions.size;
        const totalDecisions = itemIds?.length || 0;
        // If reviewer has started reviewing
        if (decisionsCount > 0) {
            // Check if any decision is rejected
            const hasRejection = assignment.decisions?.some((d) => d.decision === "Rejected");
            // Check if all pages are approved
            const allApproved = decisionsCount === totalDecisions &&
                assignment.decisions?.every((d) => d.decision === "Approved");
            if (hasRejection) {
                return {
                    type: "rejected",
                    count: decisionsCount,
                    total: totalDecisions,
                };
            }
            else if (allApproved) {
                return {
                    type: "approved",
                    count: decisionsCount,
                    total: totalDecisions,
                };
            }
            else {
                return {
                    type: "partial",
                    count: decisionsCount,
                    total: totalDecisions,
                };
            }
        }
        // Gray: Not started reviewing
        if (assignment.invitationSentDate) {
            return { type: "invited", date: assignment.invitationSentDate };
        }
        return { type: "pending" };
    };
    const StatusBadge = ({ status, }) => {
        switch (status.type) {
            case "approved":
                return (_jsxs("span", { className: "rounded-badge bg-feedback-green-light badge-pad-sm text-2xs text-feedback-green inline-flex items-center gap-1 font-medium", children: [_jsx(Check, { className: "h-2.5 w-2.5" }), status.count, "/", status.total] }));
            case "rejected":
                return (_jsxs("span", { className: "rounded-badge bg-feedback-red-light badge-pad-sm text-2xs text-feedback-red inline-flex items-center gap-1 font-medium", children: [_jsx(X, { className: "h-2.5 w-2.5" }), status.count, "/", status.total] }));
            case "partial":
                return (_jsxs("span", { className: "rounded-badge bg-feedback-orange-light badge-pad-sm text-2xs text-feedback-orange inline-flex items-center gap-1 font-medium", children: [_jsx(Clock, { className: "h-2.5 w-2.5" }), status.count, "/", status.total] }));
            case "invited":
                return (_jsxs("span", { className: "rounded-badge bg-feedback-blue-light badge-pad-sm text-2xs text-feedback-blue inline-flex items-center gap-1 font-medium", children: [_jsx(Mail, { className: "h-2.5 w-2.5" }), "Invited"] }));
            case "pending":
                return (_jsxs("span", { className: "rounded-badge bg-neutral-grey-5 badge-pad-sm text-2xs text-neutral-grey-50 inline-flex items-center gap-1 font-medium", children: [_jsx(Clock, { className: "h-2.5 w-2.5" }), "Pending"] }));
        }
    };
    const canSendInvitations = displayAssignments.some((a) => !a.invitationSentDate && selectedAssignments.has(a.assignmentId));
    return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "bg-neutral-grey-5/80 flex items-center gap-2 border-b px-3 py-2", children: [_jsx("span", { className: "text-neutral-grey-50 text-xs font-semibold tracking-wide", children: "Reviewers" }), _jsx("span", { className: "rounded-badge bg-neutral-grey-10 badge-pad-sm text-2xs text-neutral-grey-50 font-medium", children: displayAssignments.length })] }), _jsxs(SimpleToolbar, { children: [!isLimitedPreviewUser && (_jsxs(Popover, { open: isAddReviewerOpen, onOpenChange: setIsAddReviewerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SimpleIconButton, { label: "Add Reviewer", icon: _jsx(Plus, { className: "h-4 w-4" }), "data-testid": "add-reviewer-button", onClick: () => {
                                        setIsAddReviewerOpen(true);
                                        setTimeout(() => {
                                            document.getElementById("reviewer-name")?.focus();
                                        }, 100);
                                    } }) }), _jsx(PopoverContent, { className: "m-2", children: _jsxs("div", { className: "flex flex-col gap-2 p-2 text-xs", "data-testid": "add-reviewer-popover", children: [itemIds.length > 0 && language ? (_jsx(PreconfiguredReviewerSelector, { itemIds: itemIds, language: language, onReviewerSelected: async (reviewer) => {
                                                // Check if reviewer already exists (by email, case-insensitive)
                                                const exists = assignments.some((a) => a.reviewerEmail.toLowerCase() ===
                                                    reviewer.email.toLowerCase());
                                                if (!exists) {
                                                    await onAddReviewer([reviewer]);
                                                    setIsAddReviewerOpen(false);
                                                }
                                            }, existingReviewers: assignments.map((a) => ({
                                                name: a.reviewerName,
                                                email: a.reviewerEmail,
                                            })) })) : (_jsx("div", { className: "text-neutral-grey-50 mb-2 text-xs", children: !language
                                                ? "Language not available"
                                                : itemIds.length === 0
                                                    ? "No items in review"
                                                    : "Predefined reviewers not available" })), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("label", { className: "text-neutral-grey-100 text-xs font-medium", children: "New Reviewer" }), _jsx("label", { htmlFor: "reviewer-name", children: "Name" }), _jsx(Input, { id: "reviewer-name", className: "w-full", value: newReviewer?.name, onChange: (e) => {
                                                        setNewReviewer((x) => ({
                                                            ...x,
                                                            name: e.target.value,
                                                        }));
                                                    }, autoFocus: true }), showErrors && !newReviewer?.name && (_jsx("small", { className: "text-feedback-red", children: "Name is required" })), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("label", { htmlFor: "reviewer-email", children: "Email" }), _jsx(Input, { id: "reviewer-email", className: "w-full", value: newReviewer?.email, onChange: (e) => {
                                                                setNewReviewer((x) => ({
                                                                    ...x,
                                                                    email: e.target.value,
                                                                }));
                                                            } }), showErrors && !isValidEmail(newReviewer.email) && (_jsx("small", { className: "text-feedback-red", children: "Not a valid email address" })), showErrors && emailAlreadyExists(newReviewer.email) && (_jsx("small", { className: "text-feedback-red", children: "Email already exists" }))] }), _jsx(Button, { disabled: waiting, "data-testid": "add-reviewer-submit-button", onClick: handleAddReviewer, children: waiting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Adding..."] })) : (_jsxs(_Fragment, { children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "Add Reviewer"] })) })] })] }) })] })), !isLimitedPreviewUser && canSendInvitations && (_jsx(SimpleIconButton, { label: "Send Invitations", icon: _jsx(Send, { className: "h-4 w-4" }), onClick: handleSendInvitations, disabled: loading }))] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: displayAssignments.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 flex h-full items-center justify-center text-sm", children: "No reviewers assigned" })) : (_jsxs("table", { className: "w-full text-xs", children: [_jsx("thead", { className: "bg-neutral-grey-5/95 sticky top-0 backdrop-blur-sm", children: _jsxs("tr", { className: "text-neutral-grey-50 border-b text-left text-[10px] font-medium tracking-wider", children: [!isLimitedPreviewUser && (_jsx("th", { className: "w-8 px-2 py-1.5", children: _jsx(Checkbox, { checked: displayAssignments.filter((a) => !a.invitationSentDate)
                                                .length > 0 &&
                                                displayAssignments
                                                    .filter((a) => !a.invitationSentDate)
                                                    .every((a) => selectedAssignments.has(a.assignmentId)), onCheckedChange: (checked) => {
                                                const newSet = new Set(selectedAssignments);
                                                displayAssignments
                                                    .filter((a) => !a.invitationSentDate)
                                                    .forEach((a) => {
                                                    if (checked) {
                                                        newSet.add(a.assignmentId);
                                                    }
                                                    else {
                                                        newSet.delete(a.assignmentId);
                                                    }
                                                });
                                                setSelectedAssignments(newSet);
                                            }, className: "h-3 w-3" }) })), _jsx("th", { className: "px-2 py-1.5", children: "Name" }), _jsx("th", { className: "px-2 py-1.5", children: "Email" }), _jsx("th", { className: "px-2 py-1.5 text-center", children: "Status" }), !isLimitedPreviewUser && (_jsx("th", { className: "w-16 px-2 py-1.5 text-right", children: "Actions" }))] }) }), _jsx("tbody", { children: displayAssignments.map((assignment) => {
                                const status = getReviewerStatus(assignment);
                                const displayName = assignment.reviewerName ||
                                    assignment.reviewerEmail ||
                                    "Reviewer";
                                const hasError = invitationErrors.has(assignment.assignmentId);
                                return (_jsxs("tr", { className: cn("group border-border-default cursor-pointer border-b transition-colors", selectedReviewerId === assignment.assignmentId
                                        ? "bg-feedback-blue-light/60"
                                        : "hover:bg-neutral-grey-5/50"), onClick: () => onSelectReviewer(assignment.assignmentId), children: [!isLimitedPreviewUser && (_jsx("td", { className: "px-2 py-1.5", onClick: (e) => e.stopPropagation(), children: !assignment.invitationSentDate && (_jsx(Checkbox, { checked: selectedAssignments.has(assignment.assignmentId), onCheckedChange: (checked) => {
                                                    const newSet = new Set(selectedAssignments);
                                                    if (checked) {
                                                        newSet.add(assignment.assignmentId);
                                                    }
                                                    else {
                                                        newSet.delete(assignment.assignmentId);
                                                    }
                                                    setSelectedAssignments(newSet);
                                                }, className: "h-3 w-3" })) })), _jsxs("td", { className: "max-w-[120px] px-2 py-1.5", children: [_jsx("span", { className: "text-neutral-grey-100 block truncate font-medium", title: displayName, children: displayName }), hasError && (_jsx("span", { className: "text-feedback-red block truncate text-[10px]", children: invitationErrors.get(assignment.assignmentId) }))] }), _jsx("td", { className: "max-w-[140px] px-2 py-1.5", children: _jsx("span", { className: "text-neutral-grey-50 block truncate", title: assignment.reviewerEmail, children: assignment.reviewerEmail || "—" }) }), _jsx("td", { className: "px-2 py-1.5 text-center", children: _jsx(StatusBadge, { status: status }) }), !isLimitedPreviewUser && (_jsx("td", { className: "px-2 py-1.5 text-right", onClick: (e) => e.stopPropagation(), children: _jsxs("div", { className: "flex items-center justify-end gap-0.5 opacity-0 transition-opacity group-hover:opacity-100", children: [_jsx(Button, { variant: "ghost", size: "sm", className: "text-neutral-grey-50 hover:text-feedback-blue h-5 w-5 p-0", onClick: async (e) => {
                                                            e.stopPropagation();
                                                            const assignmentId = assignment.assignmentId;
                                                            setSendingInvitations(new Set([...sendingInvitations, assignmentId]));
                                                            const newErrors = new Map(invitationErrors);
                                                            newErrors.delete(assignmentId);
                                                            setInvitationErrors(newErrors);
                                                            try {
                                                                await onSendInvitations([assignmentId]);
                                                            }
                                                            catch (err) {
                                                                let errorMessage = err instanceof Error
                                                                    ? err.message
                                                                    : "Failed to send invitation";
                                                                if (typeof errorMessage !== "string") {
                                                                    errorMessage = String(errorMessage);
                                                                }
                                                                if (err &&
                                                                    typeof err === "object" &&
                                                                    "assignmentErrors" in err) {
                                                                    const assignmentErrorMap = err
                                                                        .assignmentErrors;
                                                                    if (assignmentErrorMap &&
                                                                        assignmentErrorMap.has(assignmentId)) {
                                                                        const specificError = assignmentErrorMap.get(assignmentId);
                                                                        if (specificError &&
                                                                            typeof specificError === "string") {
                                                                            errorMessage = specificError;
                                                                        }
                                                                    }
                                                                }
                                                                const newErrorMap = new Map(invitationErrors);
                                                                newErrorMap.set(assignmentId, errorMessage);
                                                                setInvitationErrors(newErrorMap);
                                                            }
                                                            finally {
                                                                const newSending = new Set(sendingInvitations);
                                                                newSending.delete(assignmentId);
                                                                setSendingInvitations(newSending);
                                                            }
                                                        }, disabled: loading ||
                                                            sendingInvitations.has(assignment.assignmentId), title: assignment.invitationSentDate
                                                            ? "Resend invitation"
                                                            : "Send invitation", children: sendingInvitations.has(assignment.assignmentId) ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin" })) : (_jsx(Send, { className: "h-3 w-3" })) }), _jsx(Button, { variant: "ghost", size: "sm", className: "text-neutral-grey-50 hover:text-feedback-red h-5 w-5 p-0", onClick: (e) => {
                                                            e.stopPropagation();
                                                            const reviewerName = assignment.reviewerName ||
                                                                assignment.reviewerEmail;
                                                            editContext?.confirm({
                                                                header: "Remove Reviewer",
                                                                message: `Are you sure you want to remove ${reviewerName} from this review?`,
                                                                acceptLabel: "Remove",
                                                                showCancel: true,
                                                                accept: async () => {
                                                                    await onRemoveReviewer(assignment.assignmentId);
                                                                },
                                                            });
                                                        }, disabled: loading, title: "Remove reviewer", children: _jsx(X, { className: "h-3 w-3" }) })] }) }))] }, assignment.assignmentId));
                            }) })] })) })] }));
}
//# sourceMappingURL=ReviewersPanel.js.map