<!--
  - @copyright 2023 Christopher Ng <chrng8@gmail.com>
  -
  - @author Christopher Ng <chrng8@gmail.com>
  -
  - @license AGPL-3.0-or-later
  -
  - This program is free software: you can redistribute it and/or modify
  - it under the terms of the GNU Affero General Public License as
  - published by the Free Software Foundation, either version 3 of the
  - License, or (at your option) any later version.
  -
  - This program is distributed in the hope that it will be useful,
  - but WITHOUT ANY WARRANTY; without even the implied warranty of
  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  - GNU Affero General Public License for more details.
  -
  - You should have received a copy of the GNU Affero General Public License
  - along with this program. If not, see <http://www.gnu.org/licenses/>.
  -
-->

<template>
	<NcHeaderMenu id="user-menu"
		class="user-menu"
		is-nav
		:aria-label="t('core', 'Settings menu')"
		:description="avatarDescription">
		<template #trigger>
			<NcAvatar v-if="!isLoadingUserStatus"
				class="user-menu__avatar"
				:disable-menu="true"
				:disable-tooltip="true"
				:user="userId"
				:preloaded-user-status="userStatus" />
		</template>
		<ul>
			<ProfileUserMenuEntry :id="profileEntry.id"
				:name="profileEntry.name"
				:href="profileEntry.href"
				:active="profileEntry.active" />
			<UserMenuEntry v-for="entry in otherEntries"
				:id="entry.id"
				:key="entry.id"
				:name="entry.name"
				:href="entry.href"
				:active="entry.active"
				:icon="entry.icon" />
		</ul>
	</NcHeaderMenu>
</template>

<script>
import axios from '@nextcloud/axios'
import { emit, subscribe } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
import { generateOcsUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'
import { getCapabilities } from '@nextcloud/capabilities'

import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js'
import NcHeaderMenu from '@nextcloud/vue/dist/Components/NcHeaderMenu.js'

import { getAllStatusOptions } from '../../../apps/user_status/src/services/statusOptionsService.js'
import ProfileUserMenuEntry from '../components/UserMenu/ProfileUserMenuEntry.vue'
import UserMenuEntry from '../components/UserMenu/UserMenuEntry.vue'

import logger from '../logger.js'

/**
 * @typedef SettingNavEntry
 * @property {string} id - id of the entry, used as HTML ID, for example, "settings"
 * @property {string} name - Label of the entry, for example, "Personal Settings"
 * @property {string} icon - Icon of the entry, for example, "/apps/settings/img/personal.svg"
 * @property {'settings'|'link'|'guest'} type - Type of the entry
 * @property {string} href - Link of the entry, for example, "/settings/user"
 * @property {boolean} active - Whether the entry is active
 * @property {number} order - Order of the entry
 * @property {number} unread - Number of unread pf this items
 * @property {string} classes - Classes for custom styling
 */

/** @type {Record<string, SettingNavEntry>} */
const settingsNavEntries = loadState('core', 'settingsNavEntries', [])
const { profile: profileEntry, ...otherEntries } = settingsNavEntries

const translateStatus = (status) => {
	const statusMap = Object.fromEntries(
		getAllStatusOptions()
			.map(({ type, label }) => [type, label]),
	)
	if (statusMap[status]) {
		return statusMap[status]
	}
	return status
}

export default {
	name: 'UserMenu',

	components: {
		NcAvatar,
		NcHeaderMenu,
		ProfileUserMenuEntry,
		UserMenuEntry,
	},

	data() {
		return {
			profileEntry,
			otherEntries,
			displayName: getCurrentUser()?.displayName,
			userId: getCurrentUser()?.uid,
			isLoadingUserStatus: true,
			userStatus: {
				status: null,
				icon: null,
				message: null,
			},
		}
	},

	computed: {
		translatedUserStatus() {
			return {
				...this.userStatus,
				status: translateStatus(this.userStatus.status),
			}
		},

		avatarDescription() {
			const description = [
				t('core', 'Avatar of {displayName}', { displayName: this.displayName }),
				...Object.values(this.translatedUserStatus).filter(Boolean),
			].join(' — ')
			return description
		},
	},

	async created() {
		if (!getCapabilities()?.user_status?.enabled) {
			this.isLoadingUserStatus = false
			return
		}

		const url = generateOcsUrl('/apps/user_status/api/v1/user_status')
		try {
			const response = await axios.get(url)
			const { status, icon, message } = response.data.ocs.data
			this.userStatus = { status, icon, message }
		} catch (e) {
			logger.error('Failed to load user status')
		}
		this.isLoadingUserStatus = false
	},

	mounted() {
		subscribe('user_status:status.updated', this.handleUserStatusUpdated)
		emit('core:user-menu:mounted')
	},

	methods: {
		handleUserStatusUpdated(state) {
			if (this.userId === state.userId) {
				this.userStatus = {
					status: state.status,
					icon: state.icon,
					message: state.message,
				}
			}
		},
	},
}
</script>

<style lang="scss" scoped>
.user-menu {
	margin-right: 12px;

	&:deep {
		.header-menu {
			&__trigger {
				opacity: 1 !important;
				&:focus-visible {
					.user-menu__avatar {
						border: 2px solid var(--color-primary-element);
					}
				}
			}

			&__carret {
				display: none !important;
			}

			&__content {
				width: fit-content !important;
			}
		}
	}

	&__avatar {
		&:active,
		&:focus,
		&:hover {
			border: 2px solid var(--color-primary-element-text);
		}
	}

	ul {
		display: flex;
		flex-direction: column;
		gap: 2px;

		&:deep {
			li {
				a,
				button {
					border-radius: 6px;
					display: inline-flex;
					align-items: center;
					height: var(--header-menu-item-height);
					color: var(--color-main-text);
					padding: 10px 8px;
					box-sizing: border-box;
					white-space: nowrap;
					position: relative;
					width: 100%;

					&:hover {
						background-color: var(--color-background-hover);
					}

					&:focus-visible {
						background-color: var(--color-background-hover) !important;
						box-shadow: inset 0 0 0 2px var(--color-primary-element) !important;
						outline: none !important;
					}

					&:active:not(:focus-visible),
					&.active:not(:focus-visible) {
						background-color: var(--color-primary-element);
						color: var(--color-primary-element-text);

						img {
							filter: var(--primary-invert-if-dark);
						}
					}

					span {
						padding-bottom: 0;
						white-space: nowrap;
						overflow: hidden;
						text-overflow: ellipsis;
						max-width: 210px;
					}

					img {
						width: 16px;
						height: 16px;
						margin-right: 10px;
					}

					img {
						filter: var(--background-invert-if-dark);
					}
				}

				// Override global button styles
				button {
					background-color: transparent;
					border: none;
					font-weight: normal;
					margin: 0;
				}
			}
		}
	}
}
</style>
