<template>
    <ContextMenu>
        <ContextMenuTrigger as-child>
            <Card class="friend-card p-0 gap-0" :style="cardStyle" @click="showUserDialog(friend.id)">
                <div class="friend-card__header">
                    <div>
                        <Avatar
                            class="friend-card__avatar"
                            :style="{ width: `${avatarSize}px`, height: `${avatarSize}px` }">
                            <AvatarImage :src="userImage(friend.ref, true)" />
                            <AvatarFallback>{{ avatarFallback }}</AvatarFallback>
                        </Avatar>
                    </div>
                    <span class="friend-card__status-dot" :class="statusDotClass"></span>
                    <div class="friend-card__name ml-0.5" :title="friend.name">{{ friend.name }}</div>
                </div>
                <div class="friend-card__body">
                    <div class="friend-card__signature ml-1" :title="friend.ref?.statusDescription">
                        <Pencil v-if="friend.ref?.statusDescription" class="h-3.5 w-3.5 mr-1" style="opacity: 0.7" />
                        {{ friend.ref?.statusDescription || '&nbsp;' }}
                    </div>
                    <div v-if="displayInstanceInfo" @click.stop class="friend-card__world" :title="friend.worldName">
                        <Location
                            class="friend-card__location"
                            :location="friend.ref?.location"
                            :traveling="friend.ref?.travelingToLocation"
                            link />
                    </div>
                </div>
            </Card>
        </ContextMenuTrigger>
        <ContextMenuContent>
            <ContextMenuItem v-if="friend.state === 'online'" @click="friendRequestInvite">
                {{ t('dialog.user.actions.request_invite') }}
            </ContextMenuItem>
            <ContextMenuItem v-if="isGameRunning" :disabled="!canInviteToMyLocation" @click="friendInvite">
                {{ t('dialog.user.actions.invite') }}
            </ContextMenuItem>
            <ContextMenuItem :disabled="!currentUser?.isBoopingEnabled" @click="friendSendBoop">
                {{ t('dialog.user.actions.send_boop') }}
            </ContextMenuItem>
            <ContextMenuSeparator v-if="friend.state === 'online' && hasFriendLocation" />
            <ContextMenuItem
                v-if="friend.state === 'online' && hasFriendLocation"
                :disabled="!canJoinFriend"
                @click="friendJoin">
                {{ t('dialog.user.info.launch_invite_tooltip') }}
            </ContextMenuItem>
            <ContextMenuItem
                v-if="friend.state === 'online' && hasFriendLocation"
                :disabled="!canJoinFriend"
                @click="friendInviteSelf">
                {{ t('dialog.user.info.self_invite_tooltip') }}
            </ContextMenuItem>
        </ContextMenuContent>
    </ContextMenu>
</template>

<script setup>
    import {
        ContextMenu,
        ContextMenuContent,
        ContextMenuItem,
        ContextMenuSeparator,
        ContextMenuTrigger
    } from '@/components/ui/context-menu';
    import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
    import { Card } from '@/components/ui/card';
    import { Pencil } from 'lucide-vue-next';
    import { computed } from 'vue';
    import { storeToRefs } from 'pinia';
    import { toast } from 'vue-sonner';
    import { useI18n } from 'vue-i18n';

    import { isRealInstance, parseLocation, userImage, userStatusClass } from '../../../shared/utils';
    import { useGameStore, useLaunchStore, useLocationStore, useUserStore } from '../../../stores';
    import { instanceRequest, notificationRequest, worldRequest } from '../../../api';
    import { checkCanInvite, checkCanInviteSelf } from '../../../shared/utils/invite.js';

    import Location from '../../../components/Location.vue';

    const { t } = useI18n();
    const { showUserDialog, showSendBoopDialog } = useUserStore();
    const launchStore = useLaunchStore();
    const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
    const { isGameRunning } = storeToRefs(useGameStore());
    const { currentUser } = storeToRefs(useUserStore());

    const props = defineProps({
        friend: {
            type: Object,
            required: true
        },
        cardScale: {
            type: Number,
            default: 1
        },
        displayInstanceInfo: {
            type: Boolean,
            default: true
        },
        cardSpacing: {
            type: Number,
            default: 1
        }
    });

    const avatarSize = computed(() => 48 * props.cardScale);

    const cardStyle = computed(() => ({
        '--card-scale': props.cardScale,
        '--card-spacing': props.cardSpacing,
        cursor: 'pointer',
        padding: `${24 * props.cardScale * props.cardSpacing}px`
    }));

    const avatarFallback = computed(() => props.friend?.name?.charAt(0) ?? '?');

    const statusDotClass = computed(() => {
        const status = userStatusClass(props.friend.ref, props.friend.pendingOffline);

        if (status.joinme) {
            return 'friend-card__status-dot--join';
        }
        if (status.online) {
            return 'friend-card__status-dot--online';
        }
        // sometimes appearing and sometimes disappearing
        if (status.active) {
            const friendStatus = props.friend.status;
            if (friendStatus === 'join me') {
                return 'friend-card__status-dot--active-join';
            }
            if (friendStatus === 'ask me') {
                return 'friend-card__status-dot--active-ask';
            }
            if (friendStatus === 'busy') {
                return 'friend-card__status-dot--active-busy';
            }
            return 'friend-card__status-dot--active';
        }
        if (status.askme) {
            return 'friend-card__status-dot--ask';
        }
        if (status.busy) {
            return 'friend-card__status-dot--busy';
        }
        if (status.offline) {
            return 'friend-card__status-dot--offline';
        }

        return 'friend-card__status-dot--hidden';
    });

    const canInviteToMyLocation = computed(() => checkCanInvite(lastLocation.value.location));

    const hasFriendLocation = computed(() => {
        const loc = props.friend.ref?.location;
        return !!loc && isRealInstance(loc);
    });

    const canJoinFriend = computed(() => {
        const loc = props.friend.ref?.location;
        if (!loc || !isRealInstance(loc)) return false;
        return checkCanInviteSelf(loc);
    });

    /**
     *
     */
    function friendRequestInvite() {
        notificationRequest.sendRequestInvite({ platform: 'standalonewindows' }, props.friend.id).then(() => {
            toast.success('Request invite sent');
        });
    }

    /**
     *
     */
    function friendInvite() {
        let currentLocation = lastLocation.value.location;
        if (currentLocation === 'traveling') {
            currentLocation = lastLocationDestination.value;
        }
        const L = parseLocation(currentLocation);
        worldRequest.getCachedWorld({ worldId: L.worldId }).then((args) => {
            notificationRequest
                .sendInvite(
                    {
                        instanceId: L.tag,
                        worldId: L.tag,
                        worldName: args.ref.name
                    },
                    props.friend.id
                )
                .then(() => {
                    toast.success(t('message.invite.sent'));
                });
        });
    }

    /**
     *
     */
    function friendSendBoop() {
        showSendBoopDialog(props.friend.id);
    }

    /**
     *
     */
    function friendJoin() {
        const loc = props.friend.ref?.location;
        if (!loc) return;
        launchStore.showLaunchDialog(loc);
    }

    /**
     *
     */
    function friendInviteSelf() {
        const loc = props.friend.ref?.location;
        if (!loc) return;
        const L = parseLocation(loc);
        instanceRequest
            .selfInvite({
                instanceId: L.instanceId,
                worldId: L.worldId
            })
            .then(() => {
                toast.success(t('message.invite.self_sent'));
            });
    }
</script>

<style scoped>
    .friend-card {
        --card-scale: 1;
        --card-spacing: 1;
        position: relative;
        display: grid;
        gap: calc(14px * var(--card-scale) * var(--card-spacing));
        border-radius: 8px;
        transition: background-color 0.15s ease;
        width: 100%;
        max-width: var(--friend-card-target-width, 220px);
        min-width: var(--friend-card-min-width, 220px);
        box-sizing: border-box;

        &:hover {
            background-color: var(--accent);
            box-shadow:
                0 4px 6px -1px rgb(0 0 0 / 0.1),
                0 2px 4px -2px rgb(0 0 0 / 0.1);
        }
    }

    .friend-card__header {
        display: grid;
        grid-template-columns: auto 1fr;
        align-items: flex-start;
        gap: calc(12px * var(--card-scale) * var(--card-spacing));
    }

    .friend-card__status-dot {
        position: absolute;
        top: calc(8px * var(--card-scale));
        right: calc(8px * var(--card-scale));
        inline-size: calc(12px * var(--card-scale));
        block-size: calc(12px * var(--card-scale));
        border-radius: 999px;
        pointer-events: none;
    }

    .friend-card__status-dot--hidden {
        display: none;
    }

    .friend-card__status-dot--online {
        background: #67c23a;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #67c23a 40%, transparent);
    }

    .friend-card__status-dot--active {
        background: transparent;
        border: calc(2px * var(--card-scale)) solid #67c23a;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #67c23a 40%, transparent);
    }

    .friend-card__status-dot--active-join {
        background: transparent;
        border: calc(2px * var(--card-scale)) solid #00b8ff;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #00b8ff 40%, transparent);
    }

    .friend-card__status-dot--active-ask {
        background: transparent;
        border: calc(2px * var(--card-scale)) solid #ff9500;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #ff9500 40%, transparent);
    }

    .friend-card__status-dot--active-busy {
        background: transparent;
        border: calc(2px * var(--card-scale)) solid #ff2c2c;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #ff2c2c 40%, transparent);
    }

    .friend-card__status-dot--join {
        background: #00b8ff;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #00b8ff 40%, transparent);
    }

    .friend-card__status-dot--busy {
        background: #ff2c2c;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #ff2c2c 40%, transparent);
    }

    .friend-card__status-dot--ask {
        background: #ff9500;
        box-shadow: 0 0 calc(8px * var(--card-scale)) color-mix(in oklch, #ff9500 40%, transparent);
    }

    .friend-card__status-dot--offline {
        background: #737f8d;
    }

    .friend-card__body {
        display: grid;
        gap: calc(12px * var(--card-scale) * var(--card-spacing));
    }

    .friend-card__name {
        font-size: calc(17px * var(--card-scale));
        font-weight: 600;
        line-height: 1.2;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .friend-card__signature {
        margin-top: calc(6px * var(--card-spacing));
        font-size: calc(13px * var(--card-scale));
        line-height: 1.4;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        display: flex;
        align-items: center;
    }

    .friend-card__world {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: calc(40px * var(--card-scale));
        padding: calc(6px * var(--card-scale)) calc(10px * var(--card-scale));
        border-radius: calc(10px * var(--card-scale));
        font-size: calc(12px * var(--card-scale));
        line-height: 1.3;
        box-sizing: border-box;
        max-width: 100%;
        min-width: 0;
        overflow: hidden;
    }

    :global(html.dark) .friend-card__world,
    :global(:root.dark) .friend-card__world,
    :global(:root[data-theme='dark']) .friend-card__world {
        color: var(--color-zinc-300);
    }

    .friend-card__location {
        display: flex;
        width: 100%;
        max-height: calc(36px * var(--card-scale));
        overflow: hidden;
        line-height: 1.3;
        white-space: normal;
        word-break: break-word;
        text-align: center;
    }

    .friend-card__location :deep(.x-location__text) {
        display: -webkit-box;
        overflow: hidden;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        text-overflow: ellipsis;
    }

    .friend-card__location :deep(.x-location__text:only-child) {
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: calc(24px * var(--card-scale));
    }

    .friend-card__location :deep(.x-location__text:only-child span) {
        display: block;
        width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .friend-card__location :deep(.x-location__meta) {
        display: none;
    }

    .friend-card__location :deep(.flags) {
        scale: calc(1 * var(--card-scale));
        filter: brightness(1.05);
    }
</style>
