import { Plus } from "@styled-icons/boxicons-regular";
import { observer } from "mobx-react-lite";
import { useLocation, useParams } from "react-router-dom";
import { Channel, Servers, Users } from "revolt.js/dist/api/objects";
import styled, { css } from "styled-components";

import { attachContextMenu, openContextMenu } from "preact-context-menu";

import ConditionalLink from "../../../lib/ConditionalLink";
import PaintCounter from "../../../lib/PaintCounter";
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";

import { useData } from "../../../mobx/State";
import { connectState } from "../../../redux/connector";
import { LastOpened } from "../../../redux/reducers/last_opened";
import { Unreads } from "../../../redux/reducers/unreads";

import { useIntermediate } from "../../../context/intermediate/Intermediate";
import { useClient } from "../../../context/revoltjs/RevoltClient";
import {
    useChannels,
    useForceUpdate,
    useServers,
} from "../../../context/revoltjs/hooks";

import logoSVG from "../../../assets/logo.svg";
import ServerIcon from "../../common/ServerIcon";
import Tooltip from "../../common/Tooltip";
import UserHover from "../../common/user/UserHover";
import UserIcon from "../../common/user/UserIcon";
import IconButton from "../../ui/IconButton";
import LineDivider from "../../ui/LineDivider";
import { mapChannelWithUnread } from "./common";

import { Children } from "../../../types/Preact";

function Icon({
    children,
    unread,
    size,
}: {
    children: Children;
    unread?: "mention" | "unread";
    size: number;
}) {
    return (
        <svg width={size} height={size} aria-hidden="true" viewBox="0 0 32 32">
            <use href="#serverIndicator" />
            <foreignObject
                x="0"
                y="0"
                width="32"
                height="32"
                mask={unread ? "url(#server)" : undefined}>
                {children}
            </foreignObject>
            {unread === "unread" && (
                <circle cx="27" cy="5" r="5" fill={"white"} />
            )}
            {unread === "mention" && (
                <circle cx="27" cy="5" r="5" fill={"var(--error)"} />
            )}
        </svg>
    );
}

const ServersBase = styled.div`
    width: 56px;
    height: 100%;
    display: flex;
    flex-direction: column;

    ${isTouchscreenDevice &&
    css`
        padding-bottom: 50px;
    `}
`;

const ServerList = styled.div`
    flex-grow: 1;
    display: flex;
    overflow-y: scroll;
    padding-bottom: 48px;
    flex-direction: column;

    scrollbar-width: none;

    > :first-child > svg {
        margin: 6px 0 6px 4px;
    }

    &::-webkit-scrollbar {
        width: 0px;
    }
`;

const ServerEntry = styled.div<{ active: boolean; home?: boolean }>`
    height: 58px;
    display: flex;
    align-items: center;

    > div {
        height: 42px;
        padding-left: 10px;

        display: grid;
        place-items: center;

        border-start-start-radius: 50%;
        border-end-start-radius: 50%;

        &:active {
            transform: translateY(1px);
        }

        ${(props) =>
            props.active &&
            css`
                &:active {
                    transform: none;
                }
            `}
    }

    > span {
        width: 0;
        display: relative;

        ${(props) =>
            !props.active &&
            css`
                display: none;
            `}

        svg {
            margin-top: 5px;
            display: relative;

            pointer-events: none;
            // outline: 1px solid red;
        }
    }

    ${(props) =>
        (!props.active || props.home) &&
        css`
            cursor: pointer;
        `}
`;

function Swoosh() {
    return (
        <span>
            <svg
                width="56"
                height="103"
                viewBox="0 0 56 103"
                fill="none"
                xmlns="http://www.w3.org/2000/svg">
                <path
                    d="M55.0368 51.5947C55.0368 64.8596 44.2834 75.613 31.0184 75.613C17.7534 75.613 7 64.8596 7 51.5947C7 38.3297 17.7534 27.5763 31.0184 27.5763C44.2834 27.5763 55.0368 38.3297 55.0368 51.5947Z"
                    fill="var(--sidebar-active)"
                />
                <path
                    d="M55.8809 1C55.5597 16.9971 34.4597 25.2244 24.0847 28.6715L55.8846 60.4859L55.8809 1Z"
                    fill="var(--sidebar-active)"
                />
                <path
                    d="M55.8809 102.249C55.5597 86.2516 34.4597 78.0243 24.0847 74.5771L55.8846 42.7627L55.8809 102.249Z"
                    fill="var(--sidebar-active)"
                />
            </svg>
        </span>
    );
}

interface Props {
    unreads: Unreads;
    lastOpened: LastOpened;
}

export const ServerListSidebar = observer(({ unreads, lastOpened }: Props) => {
    const store = useData();
    const client = useClient();
    const self = store.users.get(client.user!._id);

    const ctx = useForceUpdate();
    const activeServers = useServers(undefined, ctx) as Servers.Server[];
    const channels = [...store.channels.values()].map((x) =>
        mapChannelWithUnread(x, unreads),
    );

    const unreadChannels = channels
        .filter((x) => x.unread)
        .map((x) => x.channel?._id);

    const servers = activeServers.map((server) => {
        let alertCount = 0;
        for (const id of server.channels) {
            const channel = channels.find((x) => x.channel?._id === id);
            if (channel?.alertCount) {
                alertCount += channel.alertCount;
            }
        }

        return {
            ...server,
            unread: (typeof server.channels.find((x) =>
                unreadChannels.includes(x),
            ) !== "undefined"
                ? alertCount > 0
                    ? "mention"
                    : "unread"
                : undefined) as "mention" | "unread" | undefined,
            alertCount,
        };
    });

    const path = useLocation().pathname;
    const { server: server_id } = useParams<{ server?: string }>();
    const server = servers.find((x) => x!._id == server_id);

    const { openScreen } = useIntermediate();

    let homeUnread: "mention" | "unread" | undefined;
    let alertCount = 0;
    for (const x of channels) {
        if (
            (x.channel?.channel_type === "DirectMessage"
                ? x.channel?.active
                : true) &&
            x.unread
        ) {
            homeUnread = "unread";
            alertCount += x.alertCount ?? 0;
        }
    }

    if (
        [...store.users.values()].find(
            (x) => x.relationship === Users.Relationship.Incoming,
        )
    ) {
        alertCount++;
    }

    if (alertCount > 0) homeUnread = "mention";
    const homeActive =
        typeof server === "undefined" && !path.startsWith("/invite");

    return (
        <ServersBase>
            <ServerList>
                <ConditionalLink
                    active={homeActive}
                    to={lastOpened.home ? `/channel/${lastOpened.home}` : "/"}>
                    <ServerEntry home active={homeActive}>
                        <Swoosh />
                        <div
                            onContextMenu={attachContextMenu("Status")}
                            onClick={() =>
                                homeActive && openContextMenu("Status")
                            }>
                            <UserHover user={self}>
                                <Icon size={42} unread={homeUnread}>
                                    <UserIcon target={self} size={32} status />
                                </Icon>
                            </UserHover>
                        </div>
                    </ServerEntry>
                </ConditionalLink>
                <LineDivider />
                {servers.map((entry) => {
                    const active = entry!._id === server?._id;
                    const id = lastOpened[entry!._id];

                    return (
                        <ConditionalLink
                            active={active}
                            to={`/server/${entry!._id}${
                                id ? `/channel/${id}` : ""
                            }`}>
                            <ServerEntry
                                active={active}
                                onContextMenu={attachContextMenu("Menu", {
                                    server: entry!._id,
                                })}>
                                <Swoosh />
                                <Tooltip content={entry.name} placement="right">
                                    <Icon size={42} unread={entry.unread}>
                                        <ServerIcon size={32} target={entry} />
                                    </Icon>
                                </Tooltip>
                            </ServerEntry>
                        </ConditionalLink>
                    );
                })}
                <IconButton
                    onClick={() =>
                        openScreen({
                            id: "special_input",
                            type: "create_server",
                        })
                    }>
                    <Plus size={36} />
                </IconButton>
                <PaintCounter small />
            </ServerList>
        </ServersBase>
    );
});

export default connectState(ServerListSidebar, (state) => {
    return {
        unreads: state.unreads,
        lastOpened: state.lastOpened,
    };
});