import { useEffect, useState, useMemo, useCallback } from "react";
import { getAllReviews, getReviewStatus, createReview, addReviewers, removeReviewer, sendInvitations, setItemDecision, setFinalDecision, addPagesToReview, removePagesFromReview, } from "../services/reviewsService";
export function useMultiReview({ language = "en", addSocketMessageListener, }) {
    const [reviews, setReviews] = useState([]);
    const [selectedReviewId, setSelectedReviewId] = useState(null);
    const [reviewDetail, setReviewDetail] = useState(null);
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const loadReviews = useCallback(async () => {
        try {
            setLoading(true);
            setError(null);
            const result = await getAllReviews(language);
            if (result.data) {
                setReviews(result.data);
            }
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to load reviews");
        }
        finally {
            setLoading(false);
        }
    }, [language]);
    const loadReviewDetail = useCallback(async (reviewId) => {
        try {
            setLoading(true);
            setError(null);
            const result = await getReviewStatus(reviewId);
            if (result.data) {
                setReviewDetail(result.data);
            }
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to load review");
        }
        finally {
            setLoading(false);
        }
    }, []);
    const createNewReview = useCallback(async (request) => {
        try {
            setLoading(true);
            setError(null);
            const result = await createReview(request);
            if (result.data?.reviewId) {
                // Enhance items with names from the request before reloading
                if (selectedReviewId === result.data.reviewId || !selectedReviewId) {
                    const statusResult = await getReviewStatus(result.data.reviewId);
                    if (statusResult.data) {
                        // Create a map of itemId+language -> name/path from the request items
                        const nameMap = new Map();
                        request.items.forEach((item) => {
                            const key = `${item.descriptor.id}-${item.descriptor.language}`;
                            nameMap.set(key, {
                                name: item.descriptor.name,
                                path: item.descriptor.path,
                            });
                        });
                        // Enhance the items from backend with names from our map
                        const enhancedItems = statusResult.data.items.map((item) => {
                            const key = `${item.itemId}-${item.language}`;
                            const nameInfo = nameMap.get(key);
                            return {
                                ...item,
                                name: nameInfo?.name,
                                path: nameInfo?.path,
                            };
                        });
                        setReviewDetail({
                            ...statusResult.data,
                            items: enhancedItems,
                        });
                    }
                }
                await loadReviews();
                return result.data.reviewId;
            }
            return null;
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to create review");
            return null;
        }
        finally {
            setLoading(false);
        }
    }, [selectedReviewId, loadReviews]);
    const addReviewersToReview = useCallback(async (reviewId, reviewers) => {
        try {
            setLoading(true);
            setError(null);
            await addReviewers(reviewId, reviewers);
            if (selectedReviewId === reviewId) {
                await loadReviewDetail(reviewId);
            }
            await loadReviews();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to add reviewers");
        }
        finally {
            setLoading(false);
        }
    }, [selectedReviewId, loadReviewDetail, loadReviews]);
    const removeReviewerFromReview = useCallback(async (assignmentId) => {
        try {
            setLoading(true);
            setError(null);
            await removeReviewer(assignmentId);
            if (selectedReviewId && reviewDetail) {
                await loadReviewDetail(selectedReviewId);
            }
            await loadReviews();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to remove reviewer");
        }
        finally {
            setLoading(false);
        }
    }, [selectedReviewId, reviewDetail, loadReviewDetail, loadReviews]);
    const sendReviewInvitations = useCallback(async (assignmentIds) => {
        try {
            setLoading(true);
            setError(null);
            const result = await sendInvitations(assignmentIds);
            // Check if the service returned an error response
            if (result.type === "error") {
                let errorMessage = result.details || result.summary || "Failed to send invitations";
                // Ensure we have a string, not a JSON object
                if (typeof errorMessage !== "string") {
                    // Try to extract message from object
                    if (errorMessage && typeof errorMessage === "object") {
                        errorMessage = errorMessage.message ||
                            errorMessage.error ||
                            errorMessage.summary ||
                            String(errorMessage);
                    }
                    else {
                        errorMessage = String(errorMessage);
                    }
                }
                const error = new Error(errorMessage);
                setError(errorMessage);
                throw error;
            }
            // Check if the response contains errors for individual assignments
            if (result.data &&
                typeof result.data === "object" &&
                result.data !== null &&
                "errors" in result.data &&
                Array.isArray(result.data.errors) &&
                result.data.errors.length > 0) {
                // Type guard: result.data is an object with errors property
                const responseData = result.data;
                // Create a map of assignmentId -> error message
                const errorMap = new Map();
                responseData.errors.forEach((err) => {
                    // Handle both object format and ensure message is a string
                    let message = err.message || JSON.stringify(err);
                    if (typeof message !== "string") {
                        message = String(message);
                    }
                    const assignmentId = err.assignmentId;
                    if (assignmentId) {
                        errorMap.set(assignmentId, message);
                    }
                });
                // If all assignments failed, throw a general error
                if (responseData.successfulCount === 0) {
                    const errorMessages = Array.from(errorMap.values()).join("; ");
                    const error = new Error(errorMessages);
                    setError(errorMessages);
                    throw error;
                }
                // If some succeeded and some failed, throw an error with the error map
                // We'll attach it as a custom property so the UI can access it
                const error = new Error("Some invitations failed to send");
                error.assignmentErrors = errorMap;
                throw error;
            }
            if (selectedReviewId) {
                await loadReviewDetail(selectedReviewId);
            }
            await loadReviews();
        }
        catch (err) {
            const errorMessage = err instanceof Error ? err.message : "Failed to send invitations";
            setError(errorMessage);
            // Re-throw so UI components can catch and handle errors individually
            throw err;
        }
        finally {
            setLoading(false);
        }
    }, [selectedReviewId, loadReviewDetail, loadReviews]);
    const makeItemDecision = useCallback(async (assignmentId, itemId, itemLanguage, itemVersion, decision) => {
        try {
            setLoading(true);
            setError(null);
            await setItemDecision(assignmentId, itemId, itemLanguage, itemVersion, decision);
            if (selectedReviewId) {
                await loadReviewDetail(selectedReviewId);
            }
            await loadReviews();
            // Auto-rejection: If all reviewers reject an item, set final decision to rejected
            if (decision === "Rejected" && reviewDetail && selectedReviewId) {
                const itemDecisions = reviewDetail.assignments
                    .map((assignment) => {
                    const decision = assignment.decisions?.find((d) => d.itemId === itemId && d.itemLanguage === itemLanguage);
                    return decision?.decision;
                })
                    .filter(Boolean);
                // Check if all reviewers have rejected this item
                if (itemDecisions.length === reviewDetail.assignments.length &&
                    itemDecisions.every((d) => d === "Rejected")) {
                    await setFinalDecision(selectedReviewId, "Rejected");
                    await loadReviewDetail(selectedReviewId);
                    await loadReviews();
                }
            }
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to set decision");
        }
        finally {
            setLoading(false);
        }
    }, [selectedReviewId, reviewDetail, loadReviewDetail, loadReviews]);
    const setReviewFinalDecision = useCallback(async (reviewId, decision) => {
        try {
            setLoading(true);
            setError(null);
            await setFinalDecision(reviewId, decision);
            await loadReviewDetail(reviewId);
            await loadReviews();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to set final decision");
        }
        finally {
            setLoading(false);
        }
    }, [loadReviewDetail, loadReviews]);
    const addPages = useCallback(async (reviewId, items) => {
        try {
            setLoading(true);
            setError(null);
            await addPagesToReview(reviewId, items);
            if (selectedReviewId === reviewId) {
                // Enhance items with names before reloading
                const result = await getReviewStatus(reviewId);
                if (result.data) {
                    // Create a map of itemId+language -> name/path from existing items
                    const existingNameMap = new Map();
                    if (reviewDetail?.items) {
                        reviewDetail.items.forEach((item) => {
                            const key = `${item.itemId}-${item.language}`;
                            existingNameMap.set(key, {
                                name: item.name,
                                path: item.path,
                            });
                        });
                    }
                    // Add names from the items we just added
                    items.forEach((item) => {
                        const key = `${item.descriptor.id}-${item.descriptor.language}`;
                        existingNameMap.set(key, {
                            name: item.descriptor.name,
                            path: item.descriptor.path,
                        });
                    });
                    // Enhance the items from backend with names from our map
                    const enhancedItems = result.data.items.map((item) => {
                        const key = `${item.itemId}-${item.language}`;
                        const nameInfo = existingNameMap.get(key);
                        return {
                            ...item,
                            name: nameInfo?.name,
                            path: nameInfo?.path,
                        };
                    });
                    setReviewDetail({
                        ...result.data,
                        items: enhancedItems,
                    });
                }
            }
            await loadReviews();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to add pages");
        }
        finally {
            setLoading(false);
        }
    }, [selectedReviewId, reviewDetail, loadReviewDetail, loadReviews]);
    const removePages = useCallback(async (reviewId, items) => {
        try {
            setLoading(true);
            setError(null);
            await removePagesFromReview(reviewId, items);
            if (selectedReviewId === reviewId) {
                await loadReviewDetail(reviewId);
            }
            await loadReviews();
        }
        catch (err) {
            setError(err instanceof Error ? err.message : "Failed to remove pages");
        }
        finally {
            setLoading(false);
        }
    }, [selectedReviewId, loadReviewDetail, loadReviews]);
    useEffect(() => {
        loadReviews();
    }, [loadReviews]);
    useEffect(() => {
        if (selectedReviewId) {
            loadReviewDetail(selectedReviewId);
        }
    }, [selectedReviewId, loadReviewDetail]);
    useEffect(() => {
        return addSocketMessageListener((message) => {
            if (message.type === "reviews-updated" ||
                message.type === "review-updated") {
                loadReviews();
                if (selectedReviewId) {
                    loadReviewDetail(selectedReviewId);
                }
            }
        });
    }, [
        selectedReviewId,
        loadReviews,
        loadReviewDetail,
        addSocketMessageListener,
    ]);
    return useMemo(() => ({
        reviews,
        selectedReviewId,
        reviewDetail,
        loading,
        error,
        setSelectedReviewId,
        createNewReview,
        addReviewersToReview,
        removeReviewerFromReview,
        sendReviewInvitations,
        makeItemDecision,
        setReviewFinalDecision,
        addPages,
        removePages,
        refreshReviews: loadReviews,
        refreshReviewDetail: selectedReviewId
            ? () => loadReviewDetail(selectedReviewId)
            : undefined,
    }), [
        reviews,
        selectedReviewId,
        reviewDetail,
        loading,
        error,
        createNewReview,
        addReviewersToReview,
        removeReviewerFromReview,
        sendReviewInvitations,
        makeItemDecision,
        setReviewFinalDecision,
        addPages,
        removePages,
        loadReviews,
        loadReviewDetail,
    ]);
}
//# sourceMappingURL=useMultiReview.js.map