<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import AppShell from './src/components/AppShell.vue';
import {
  iconAction,
  iconAdmin,
  iconArtifact,
  iconAutomation,
  iconChecklist,
  iconClothes,
  iconDish,
  iconDreamIsland,
  iconEvent,
  iconHabitat,
  iconHome,
  iconItem,
  iconLife,
  iconPokemon,
  iconRecipe,
  iconThreads,
  type AppIcon
} from './src/icons';
import { getCurrentLocale, loadSystemWordings, onLocaleChange, setCurrentLocale } from './src/i18n';
import { api, notifyAuthChange, onAuthChange, type AuthUser, type Language } from './src/services/api';

const { t, locale } = useI18n();
const router = useRouter();
const currentUser = ref<AuthUser | null>(null);
const viewAsBusy = ref(false);
const languages = ref<Language[]>([
  { code: 'en', name: 'English', enabled: true, isDefault: true, sortOrder: 10 },
  { code: 'zh-CN', name: '简体中文', enabled: true, isDefault: false, sortOrder: 20 }
]);
let removeAuthListener: (() => void) | null = null;
let removeLocaleListener: (() => void) | null = null;

type NavBadge = {
  label: string;
  tone?: 'info' | 'success' | 'warning' | 'danger' | 'neutral';
};

type NavLinkItem = {
  label: string;
  to: string;
  icon?: AppIcon;
  badge?: NavBadge;
};

type NavGroupItem = {
  key: string;
  label: string;
  icon?: AppIcon;
  children: NavLinkItem[];
};

type NavItem = NavLinkItem | NavGroupItem;

function inDevBadge(): NavBadge {
  return { label: t('common.inDev'), tone: 'info' };
}

function can(permissionKey: string) {
  return currentUser.value?.permissions.includes(permissionKey) === true;
}

const navItems = computed<NavItem[]>(() => {
  const items: NavItem[] = [
    { label: t('nav.home'), to: '/', icon: iconHome },
    {
      key: 'pokedex',
      label: t('nav.pokedex'),
      icon: iconPokemon,
      children: [
        { label: t('nav.mainGame'), to: '/pokemon', icon: iconPokemon },
        { label: t('nav.event'), to: '/event-pokemon', icon: iconEvent }
      ]
    },
    {
      key: 'habitat-dex',
      label: t('nav.habitatDex'),
      icon: iconHabitat,
      children: [
        { label: t('nav.mainGame'), to: '/habitats', icon: iconHabitat },
        { label: t('nav.event'), to: '/event-habitats', icon: iconEvent }
      ]
    },
    {
      key: 'collections',
      label: t('nav.collections'),
      icon: iconItem,
      children: [
        { label: t('nav.mainGame'), to: '/items', icon: iconItem },
        { label: t('nav.event'), to: '/event-items', icon: iconEvent },
        { label: t('nav.ancientArtifacts'), to: '/ancient-artifacts', icon: iconArtifact }
      ]
    },
    { label: t('nav.recipes'), to: '/recipes', icon: iconRecipe },
    { label: t('nav.automation'), to: '/automation', icon: iconAutomation, badge: inDevBadge() },
    { label: t('nav.dish'), to: '/dish', icon: iconDish },
    { label: t('nav.events'), to: '/events', icon: iconEvent, badge: inDevBadge() },
    { label: t('nav.actions'), to: '/actions', icon: iconAction, badge: inDevBadge() },
    { label: t('nav.dreamIsland'), to: '/dream-island', icon: iconDreamIsland, badge: inDevBadge() },
    { label: t('nav.clothes'), to: '/clothes', icon: iconClothes, badge: inDevBadge() },
    { label: t('nav.checklist'), to: '/checklist', icon: iconChecklist },
    { label: t('nav.life'), to: '/life', icon: iconLife },
    { label: t('nav.threads'), to: '/threads', icon: iconThreads }
  ];

  if (can('admin.access')) {
    items.push({ label: t('nav.admin'), to: '/admin', icon: iconAdmin });
  }

  return items;
});

async function loadCurrentUser() {
  try {
    const response = await api.me();
    currentUser.value = response.user;
  } catch {
    currentUser.value = null;
  }
}

async function logout() {
  try {
    await api.logout();
  } catch {
    // The local session is cleared even when the server session is already gone.
  }

  currentUser.value = null;
  notifyAuthChange();
  await router.push('/');
}

async function stopViewAs() {
  if (viewAsBusy.value) {
    return;
  }

  viewAsBusy.value = true;
  try {
    const response = await api.stopViewAs();
    currentUser.value = response.user;
    notifyAuthChange();
  } finally {
    viewAsBusy.value = false;
  }
}

async function loadLanguages() {
  try {
    const loadedLanguages = await api.languages();
    if (loadedLanguages.length) {
      languages.value = loadedLanguages;
    }

    if (!languages.value.some((language) => language.code === getCurrentLocale() && language.enabled)) {
      setCurrentLocale('en');
    }

    await loadSystemWordings(getCurrentLocale());
  } catch {
    // Keep the built-in language list when the API is not ready yet.
  }
}

async function updateLocale(value: string) {
  await loadSystemWordings(value);
  setCurrentLocale(value);
}

onMounted(() => {
  void loadLanguages();
  void loadCurrentUser();
  removeAuthListener = onAuthChange(() => {
    void loadCurrentUser();
  });
  removeLocaleListener = onLocaleChange(() => {
    void loadLanguages();
  });
});

onUnmounted(() => {
  removeAuthListener?.();
  removeLocaleListener?.();
});
</script>

<template>
  <AppShell
    :current-user="currentUser"
    :languages="languages"
    :locale="locale"
    :nav-items="navItems"
    :view-as-busy="viewAsBusy"
    @logout="logout"
    @stop-view-as="stopViewAs"
    @update:locale="updateLocale"
  >
    <NuxtPage :key="locale" />
  </AppShell>
</template>
