/*
Copyright 2024 New Vector Ltd.
Copyright 2023 The Matrix.org Foundation C.I.C.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

import React, { useEffect, useState } from "react";
import { type PollAnswerSubevent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
import { type MatrixEvent, type Poll, PollEvent, type Relations } from "matrix-js-sdk/src/matrix";
import { PollsEndIcon } from "@vector-im/compound-design-tokens/assets/web/icons";

import { _t } from "../../../../languageHandler";
import { formatLocalDateShort } from "../../../../DateUtils";
import { allVotes, collectUserVotes, countVotes } from "../../messages/MPollBody";
import { PollOption } from "../../polls/PollOption";
import { Caption } from "../../typography/Caption";
import AccessibleButton from "../../elements/AccessibleButton.tsx";

interface Props {
    event: MatrixEvent;
    poll: Poll;
    onClick: () => void;
}

type EndedPollState = {
    winningAnswers: {
        answer: PollAnswerSubevent;
        voteCount: number;
        optionNumber: number;
    }[];
    totalVoteCount: number;
};
const getWinningAnswers = (poll: Poll, responseRelations: Relations): EndedPollState => {
    const userVotes = collectUserVotes(allVotes(responseRelations));
    const votes = countVotes(userVotes, poll.pollEvent);
    const totalVoteCount = [...votes.values()].reduce((sum, vote) => sum + vote, 0);
    const winCount = Math.max(...votes.values());

    return {
        totalVoteCount,
        winningAnswers: poll.pollEvent.answers
            .map((answer, index) => ({ answerIndex: index, answer })) // keep track of original answer index
            .filter(({ answer }) => votes.get(answer.id) === winCount)
            .map(({ answer, answerIndex }) => ({
                answer,
                voteCount: votes.get(answer.id) || 0,
                optionNumber: answerIndex + 1,
            })),
    };
};

/**
 * Get deduplicated and validated poll responses
 * Will use cached responses from Poll instance when existing
 * Updates on changes to Poll responses (paging relations or from sync)
 * Returns winning answers and total vote count
 */
const usePollVotes = (poll: Poll): Partial<EndedPollState> => {
    const [results, setResults] = useState({ totalVoteCount: 0 });

    useEffect(() => {
        const getResponses = async (): Promise<void> => {
            const responseRelations = await poll.getResponses();
            setResults(getWinningAnswers(poll, responseRelations));
        };
        const onPollResponses = (responseRelations: Relations): void =>
            setResults(getWinningAnswers(poll, responseRelations));
        poll.on(PollEvent.Responses, onPollResponses);

        getResponses();

        return () => {
            poll.off(PollEvent.Responses, onPollResponses);
        };
    }, [poll]);

    return results;
};

/**
 * Render an ended poll with the winning answer and vote count
 * @param event - the poll start MatrixEvent
 * @param poll - Poll instance
 */
export const PollListItemEnded: React.FC<Props> = ({ event, poll, onClick }) => {
    const pollEvent = poll.pollEvent;
    const { winningAnswers, totalVoteCount } = usePollVotes(poll);
    if (!pollEvent) {
        return null;
    }
    const formattedDate = formatLocalDateShort(event.getTs());

    return (
        <li data-testid={`pollListItem-${event.getId()!}`} className="mx_PollListItemEnded">
            <AccessibleButton
                className="mx_PollListItemEnded_content"
                title={_t("right_panel|poll|view_poll")}
                placement="top"
                onClick={onClick}
            >
                <div className="mx_PollListItemEnded_title">
                    <PollsEndIcon className="mx_PollListItemEnded_icon" />
                    <span className="mx_PollListItemEnded_question">{pollEvent.question.text}</span>
                    <Caption>{formattedDate}</Caption>
                </div>
                {!!winningAnswers?.length && (
                    <div className="mx_PollListItemEnded_answers">
                        {winningAnswers?.map(({ answer, voteCount, optionNumber }) => (
                            <PollOption
                                key={answer.id}
                                answer={answer}
                                voteCount={voteCount}
                                totalVoteCount={totalVoteCount!}
                                pollId={poll.pollId}
                                optionNumber={optionNumber}
                                displayVoteCount
                                isChecked
                                isEnded
                            />
                        ))}
                    </div>
                )}
                <div className="mx_PollListItemEnded_voteCount">
                    <Caption>{_t("right_panel|poll|final_result", { count: totalVoteCount })}</Caption>
                </div>
            </AccessibleButton>
        </li>
    );
};
