import { ArrowBack } from "@styled-icons/boxicons-regular";
import { autorun } from "mobx";
import { useHistory, useParams } from "react-router-dom";
import { RetrievedInvite } from "revolt-api/types/Invites";

import styles from "./Invite.module.scss";
import { Text } from "preact-i18n";
import { useContext, useEffect, useState } from "preact/hooks";

import { defer } from "../../lib/defer";
import { TextReact } from "../../lib/i18n";

import { dispatch } from "../../redux";

import RequiresOnline from "../../context/revoltjs/RequiresOnline";
import {
    AppContext,
    ClientStatus,
    StatusContext,
} from "../../context/revoltjs/RevoltClient";
import { takeError } from "../../context/revoltjs/util";

import ServerIcon from "../../components/common/ServerIcon";
import UserIcon from "../../components/common/user/UserIcon";
import Button from "../../components/ui/Button";
import Overline from "../../components/ui/Overline";
import Preloader from "../../components/ui/Preloader";

export default function Invite() {
    const history = useHistory();
    const client = useContext(AppContext);
    const status = useContext(StatusContext);
    const { code } = useParams<{ code: string }>();
    const [processing, setProcessing] = useState(false);
    const [error, setError] = useState<string | undefined>(undefined);
    const [invite, setInvite] = useState<RetrievedInvite | undefined>(
        undefined,
    );

    useEffect(() => {
        if (
            typeof invite === "undefined" &&
            (status === ClientStatus.ONLINE || status === ClientStatus.READY)
        ) {
            client
                .fetchInvite(code)
                .then((data) => setInvite(data))
                .catch((err) => setError(takeError(err)));
        }
    }, [client, code, invite, status]);

    if (typeof invite === "undefined") {
        return (
            <div className={styles.preloader}>
                <RequiresOnline>
                    {error ? (
                        <Overline type="error" error={error} />
                    ) : (
                        <Preloader type="spinner" />
                    )}
                </RequiresOnline>
            </div>
        );
    }

    // ! FIXME: add i18n translations
    return (
        <div
            className={styles.invite}
            style={{
                backgroundImage: invite.server_banner
                    ? `url('${client.generateFileURL(invite.server_banner)}')`
                    : undefined,
            }}>
            <div className={styles.leave}>
                <ArrowBack size={32} onClick={() => history.push("/")} />
            </div>

            {!processing && (
                <div className={styles.icon}>
                    <ServerIcon
                        attachment={invite.server_icon}
                        server_name={invite.server_name}
                        size={64}
                    />
                </div>
            )}

            <div className={styles.details}>
                {processing ? (
                    <Preloader type="ring" />
                ) : (
                    <>
                        <h1>{invite.server_name}</h1>
                        <h2>
                            #{invite.channel_name} •{" "}
                            <Text
                                id="app.special.invite.user_count"
                                fields={{
                                    member_count: invite.member_count,
                                }}
                            />
                        </h2>
                        <h3>
                            <TextReact
                                id="app.special.invite.invited_by"
                                fields={{
                                    user: (
                                        <>
                                            <UserIcon
                                                size={24}
                                                attachment={invite.user_avatar}
                                            />{" "}
                                            {invite.user_name}
                                        </>
                                    ),
                                }}
                            />
                        </h3>
                        <Overline type="error" error={error} />
                        <Button
                            contrast
                            onClick={async () => {
                                if (status === ClientStatus.READY) {
                                    return history.push("/");
                                }

                                try {
                                    setProcessing(true);

                                    if (invite.type === "Server") {
                                        if (
                                            client.servers.get(invite.server_id)
                                        ) {
                                            history.push(
                                                `/server/${invite.server_id}/channel/${invite.channel_id}`,
                                            );
                                        }

                                        const dispose = autorun(() => {
                                            const server = client.servers.get(
                                                invite.server_id,
                                            );

                                            defer(() => {
                                                if (server) {
                                                    dispatch({
                                                        type: "UNREADS_MARK_MULTIPLE_READ",
                                                        channels:
                                                            server.channel_ids,
                                                    });

                                                    history.push(
                                                        `/server/${server._id}/channel/${invite.channel_id}`,
                                                    );
                                                }
                                            });

                                            dispose();
                                        });
                                    }

                                    await client.joinInvite(code);
                                } catch (err) {
                                    setError(takeError(err));
                                    setProcessing(false);
                                }
                            }}>
                            {status === ClientStatus.READY ? (
                                <Text id="app.special.invite.login" />
                            ) : (
                                <Text id="app.special.invite.accept" />
                            )}
                        </Button>
                    </>
                )}
            </div>
        </div>
    );
}
