﻿<script setup>
import {ref, markRaw} from 'vue';
import {useCreatorProfileStore} from '@/stores/creatorProfileStore.js';
import {useUserProfileStore} from "@/stores/userProfileStore.js";
import {useClient} from '@/plugins/api.js';
import {useRouter} from 'vue-router';
import SocialsDialog from './creators/SocialsDialog.vue';
import AliasDialog from "@/views/profile/account/AliasDialog.vue";
import FullnameDialog from "@/views/profile/account/FullnameDialog.vue";
import EmailDialog from "@/views/profile/account/EmailDialog.vue";
import ChangePasswordDialog from "@/views/profile/account/ChangePasswordDialog.vue";
import ChangeStripeIdDialog from '@/views/profile/creators/ChangeStripeIdDialog.vue';
import ChangeNameDialog from '@/views/profile/creators/ChangeNameDialog.vue';
import ChangeSlugDialog from '@/views/profile/creators/ChangeSlugDialog.vue';
import ChangeTitleDialog from '@/views/profile/creators/ChangeTitleDialog.vue';
import ChangePhoneDialog from '@/views/profile/creators/ChangePhoneDialog.vue';
import ChangeEmailDialog from '@/views/profile/creators/ChangeEmailDialog.vue';
import Youtube from "@/views/svg/Youtube.vue";
import Web from "@/views/svg/Web.vue";
import Reddit from "@/views/svg/Reddit.vue";
import X from "@/views/svg/X.vue";
import Linkedin from "@/views/svg/Linkedin.vue";
import Tiktok from "@/views/svg/Tiktok.vue";
import Instagram from "@/views/svg/Instagram.vue";
import Facebook from "@/views/svg/Facebook.vue";
import {useI18n} from 'vue-i18n';
import QRCodeVue from 'qrcode.vue';

const {t} = useI18n();
const router = useRouter();
const userProfileStore = useUserProfileStore()
const creatorProfileStore = useCreatorProfileStore();
const baseURL = window.location.origin;
const client = useClient();

// Copy URL state
const copySuccess = ref(false);
const copyButtonRef = ref(null);

async function copyCreatorUrl() {
  try {
    const url = `${baseURL}/@${creatorProfileStore.creator.slug}`;
    await navigator.clipboard.writeText(url);
    copySuccess.value = true;
    setTimeout(() => {
      copySuccess.value = false;
    }, 2000);
  } catch (err) {
    console.error('Failed to copy:', err);
  }
}

// ### Fullname
const dialogEditFullnameShown = ref(false)

function openEditFullname() {
  dialogEditFullnameShown.value = true
}

function handleCloseEditFullname() {
  dialogEditFullnameShown.value = false
}

function handleSaveEditFullname(firstname, lastname) {
  userProfileStore.changeFullname(firstname, lastname)
  dialogEditFullnameShown.value = false
}

// ### Alias
const dialogEditAliasShown = ref(false)

function openEditAlias() {
  dialogEditAliasShown.value = true
}

function handleCloseEditAlias() {
  dialogEditAliasShown.value = false
}

function handleSaveEditAlias(alias) {
  userProfileStore.changeAlias(alias)
  dialogEditAliasShown.value = false
}

// ### Email
const dialogEditEmailShown = ref(false)

function openEditEmail() {
  dialogEditEmailShown.value = true
}

function handleCloseEditEmail() {
  dialogEditEmailShown.value = false
}

function handleSaveEditEmail(email) {
  userProfileStore.changeEmail(email)
  dialogEditEmailShown.value = false
}

const dialogShown = ref(false);
const currentComponent = ref('');
const restoreDialogShown = ref(false);
const deleteDialogShown = ref(false);

const componentsMap = {
  EmailDialog: markRaw(EmailDialog),
  ChangePasswordDialog: markRaw(ChangePasswordDialog),
  SocialsDialog: markRaw(SocialsDialog),
  ChangeSlugDialog: markRaw(ChangeSlugDialog),
  ChangeNameDialog: markRaw(ChangeNameDialog),
  ChangeTitleDialog: markRaw(ChangeTitleDialog),
  ChangeStripeIdDialog: markRaw(ChangeStripeIdDialog),
  ChangePhoneDialog: markRaw(ChangePhoneDialog),
  ChangeEmailDialog: markRaw(ChangeEmailDialog),
};

function requestCancel() {
  currentComponent.value = null;
  dialogShown.value = false;
}

const openDialog = (component) => {
  currentComponent.value = componentsMap[component];
  dialogShown.value = true;
};

const closeDialog = () => {
  currentComponent.value = null;
  dialogShown.value = false;
};

function handleRestore() {
  creatorProfileStore.restoreCreatorPage();
  restoreDialogShown.value = false;
}

function handleDelete() {
  creatorProfileStore.removeCreatorPage();
  deleteDialogShown.value = false;
}

function downloadQRCode() {
  try {
    // Get the SVG element
    const svgElement = document.querySelector('.qr-code svg') || 
                      document.querySelector('.qr-container svg') ||
                      document.querySelector('svg[class*="qr"]');
    
    if (!svgElement) {
      console.error('QR code SVG element not found');
      return;
    }

    // Create a Blob from the SVG
    const svgData = new XMLSerializer().serializeToString(svgElement);
    const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
    const svgUrl = URL.createObjectURL(svgBlob);

    // Create an image element
    const img = new Image();
    img.onload = () => {
      // Set padding
      const padding = 20; // 20 pixels padding on each side
      
      // Create canvas with padding
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      
      // Set canvas size to include padding
      canvas.width = img.width + (padding * 2);
      canvas.height = img.height + (padding * 2);
      
      // Fill white background for entire canvas (including padding)
      ctx.fillStyle = 'white';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      
      // Draw the image with padding offset
      ctx.drawImage(img, padding, padding);
      
      // Convert to PNG
      const pngUrl = canvas.toDataURL('image/png');
      
      // Create download link
      const downloadLink = document.createElement('a');
      downloadLink.href = pngUrl;
      downloadLink.download = `hutopy-qr-${creatorProfileStore.creator.slug}.png`;
      
      // Trigger download
      document.body.appendChild(downloadLink);
      downloadLink.click();
      document.body.removeChild(downloadLink);
      
      // Cleanup
      URL.revokeObjectURL(svgUrl);
    };
    
    img.onerror = (error) => {
      console.error('Error loading SVG:', error);
    };
    
    // Load the SVG into the image
    img.src = svgUrl;
  } catch (error) {
    console.error('Error in downloadQRCode:', error);
  }
}

async function deconfigureStripe() {
  try {
    await client.post(`/api/membership/stripe-account`, {
      stripeAccountId: '',
    });
    await creatorProfileStore.fetchCreatorProfile();
  } catch (error) {
    console.error('Error deconfiguring stripe:', error);
  }
}
</script>

<template>

  <div class="min-h-screen w-full">
    <div class="flex flex-col items-center gap-4 m-4">

      <div class="card">

        <div class="card-title">
          {{ t('personalInfo') }}
        </div>

        <div class="content">
          <button
              class="action"
              @click="openEditFullname">
            <span class="label">{{ t('fullName') }}</span>
            <span class="value">{{ userProfileStore.fullname }}</span>
            <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
          </button>

          <button
              class="action"
              @click="openEditAlias">
            <span class="label">{{ t('alias') }}</span>
            <span class="value">{{ userProfileStore.user.alias }}</span>
            <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
          </button>
        </div>

        <div class="content">
          <button class="action" @click="openDialog('EmailDialog')">
            <span class="label">{{ t('email') }}</span>
            <span class="value">{{ userProfileStore.user.email }}</span>
            <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
          </button>
        </div>

        <div class="content">
          <button class="action" @click="openDialog('ChangePasswordDialog')">
            <span class="label">{{ t('changePassword') }}</span>
            <span class="value">••••••••</span>
            <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
          </button>
        </div>
        
      </div>

      <template v-if="creatorProfileStore.hasCreator">
        <div class="card">
          <div class="card-title">
            {{ t('creatorInfo') }}
          </div>
          <div class="content">

            <div class="action" @click="openDialog('ChangeSlugDialog')">
              <span class="label">{{ t('handle') }}</span>
              <span class="value">{{ baseURL }}/@{{ creatorProfileStore.creator.slug }}</span>
              <button 
                ref="copyButtonRef"
                class="copy-button" 
                @click.stop="copyCreatorUrl"
                :class="{ 'success': copySuccess }"
              >
                <v-icon>{{ copySuccess ? 'mdi-check' : 'mdi-content-copy' }}</v-icon>
              </button>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </div>

            <!-- NAME -->
            <button class="action" @click="openDialog('ChangeNameDialog')">
              <span class="label">{{ t('name') }}</span>
              <span class="value">{{ creatorProfileStore.creator.name }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <!-- TITLE -->
            <button class="action" @click="openDialog('ChangeTitleDialog')">
              <span class="label">{{ t('title') }}</span>
              <span class="value">{{ creatorProfileStore.creator.title }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <!-- PHONE NUMBER -->
            <button class="action" @click="openDialog('ChangePhoneDialog')">
              <span class="label">{{ t('phoneNumber') }}</span>
              <span class="value" :class="{ 'not-set': !creatorProfileStore.creator.presentation?.phoneNumber }">
                {{ creatorProfileStore.creator.presentation?.phoneNumber || t('notSet') }}
              </span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <!-- EMAIL -->
            <button class="action" @click="openDialog('ChangeEmailDialog')">
              <span class="label">{{ t('email') }}</span>
              <span class="value" :class="{ 'not-set': !creatorProfileStore.creator.presentation?.email }">
                {{ creatorProfileStore.creator.presentation?.email || t('notSet') }}
              </span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

          </div>
        </div>

        <div class="card">

          <div class="card-title">
            {{ t('payment-information') }}
          </div>

          <div class="content">
            <div class="stripe-status">
              <span class="label">{{ t('stripeStatus') }}</span>
              <span class="value" :class="{ 'configured': creatorProfileStore.creator.acceptDonation }">
                {{ creatorProfileStore.creator.acceptDonation ? t('configured') : t('notConfigured') }}
              </span>
              <div class="stripe-actions">
                <button class="configure-stripe-button" @click="openDialog('ChangeStripeIdDialog')">
                  <v-icon>mdi-credit-card</v-icon>
                  {{ t('configureStripe') }}
                </button>
                <button v-if="creatorProfileStore.creator.acceptDonation" 
                        class="deconfigure-stripe-button" 
                        @click="deconfigureStripe">
                  <v-icon>mdi-credit-card-off</v-icon>
                  {{ t('deconfigureStripe') }}
                </button>
              </div>
            </div>
          </div>

        </div>

        <div class="card">
          <div class="card-title">
            {{ t('socialNetworks') }}
          </div>
          <div class="content">

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <facebook class="social-icon"></facebook>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.facebookUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <instagram class="social-icon"></instagram>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.instagramUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <x class="social-icon"></x>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.xUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <linkedin class="social-icon"></linkedin>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.linkedInUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <tiktok class="social-icon"></tiktok>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.tikTokUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <youtube class="social-icon"></youtube>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.youtubeUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <reddit class="social-icon"></reddit>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.redditUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

            <button class="action" @click="openDialog('SocialsDialog')">
              <span class="label">
                <web class="social-icon"></web>
              </span>
              <span class="value">{{ creatorProfileStore.creator.socials?.websiteUrl }}</span>
              <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
            </button>

          </div>
        </div>

        <div class="card">
          <div class="card-title">
            {{ t('qrCode') }}
          </div>
          <div class="content">
            <div class="qr-container">
              <p class="qr-text">{{ t('qrCodeDescription') }}</p>
              <QRCodeVue
                  v-if="creatorProfileStore.creator"
                  :value="baseURL + '/@' + creatorProfileStore.creator.slug"
                  :size="200"
                  level="H"
                  render-as="svg"
                  class="qr-code"
              />
              <button 
                v-if="creatorProfileStore.creator"
                class="download-button"
                @click="downloadQRCode"
              >
                <v-icon>mdi-download</v-icon>
                {{ t('downloadQRCode') }}
              </button>
            </div>
          </div>
        </div>

        <div class="card">
          <div class="card-title">
            {{ t('dangerZone') }}
          </div>
          <div class="content">
            <span class="p-2">
              {{ t('dangerZoneWarning') }}
            </span>
            <div class="p-2">
              <button v-if="!creatorProfileStore.creator.isDeleted"
                      class="primary danger-action"
                      @click="deleteDialogShown = true">
                {{ t('deleteCreatorPage') }}
              </button>
              <button v-else
                      class="primary safe-action"
                      @click="restoreDialogShown = true">
                {{ t('restoreCreatorPage') }}
              </button>
            </div>
          </div>
        </div>
      </template>

    </div>
  </div>

  <v-dialog v-model="dialogEditFullnameShown">
    <FullnameDialog
        :firstname="userProfileStore.user.firstname"
        :lastname="userProfileStore.user.lastname"
        @close="handleCloseEditFullname"
        @save="handleSaveEditFullname"
    />
  </v-dialog>
  <v-dialog v-model="dialogEditAliasShown">
    <alias-dialog
        :alias="userProfileStore.user.alias"
        @close="handleCloseEditAlias"
        @save="handleSaveEditAlias"
    ></alias-dialog>
  </v-dialog>
  <v-dialog v-model="dialogShown">
    <component
        :is="currentComponent"
        :creator="creatorProfileStore.creator"
        :email="userProfileStore.user.email"
        @closeRequested="closeDialog"
    ></component>
  </v-dialog>
  <v-dialog v-model="restoreDialogShown">
    <div class="card dialog">
      <div class="card-title">{{ t('restoreCreatorPage') }}</div>
      <div class="card-content">
        <p>{{ t('restoreWarning') }}</p>
        <div class="card-actions">
          <button class="secondary" @click="restoreDialogShown = false">
            {{ t('cancel') }}
          </button>
          <button class="primary" @click="handleRestore">
            {{ t('accept') }}
          </button>
        </div>
      </div>
    </div>
  </v-dialog>
  <v-dialog v-model="deleteDialogShown">
    <div class="card dialog">
      <div class="card-title">{{ t('deleteCreatorPage') }}</div>
      <div class="card-content">
        <p>{{ t('deleteWarning') }}</p>
        <div class="card-actions">
          <button class="secondary" @click="deleteDialogShown = false">
            {{ t('cancel') }}
          </button>
          <button class="primary danger-action" @click="handleDelete">
            {{ t('accept') }}
          </button>
        </div>
      </div>
    </div>
  </v-dialog>

</template>

<style scoped>
.card {
  @apply rounded-lg p-4 w-full;
}

.card-title {
  @apply text-hOnBackground text-lg font-bold;
}

.content {
  @apply flex flex-col gap-2;
}

.action {
  @apply flex flex-row items-center w-full p-3 rounded-lg;
  @apply hover:bg-hSurface;
  @apply transition-colors duration-500;
}

.label {
  @apply text-hOnBackground w-[200px] text-left;
  @apply flex items-center justify-start;
}

.copy-button {
  @apply ml-2 p-1 rounded-full;
  @apply transition-all duration-300;
  @apply relative overflow-hidden;
  @apply opacity-60;
}

.copy-button:hover {
  @apply opacity-100;
  @apply bg-hSurface;
}

.copy-button::after {
  content: '';
  @apply absolute inset-0 bg-white/20;
  @apply scale-0 rounded-full;
  @apply transition-transform duration-300;
}

.copy-button:active::after {
  @apply scale-150;
  @apply opacity-0;
}

.copy-button.success {
  @apply bg-green-500/20;
  @apply opacity-100;
}

.value {
  @apply text-hOnBackground flex-1 text-center;
  @apply flex items-center justify-center;
}

.value.not-set {
  @apply text-gray-400;
}

.chevron {
  @apply text-hOnBackground w-[40px] text-right;
  @apply flex items-center justify-end;
}

.social-icon {
  @apply fill-current w-6 h-6;
  @apply text-hOnBackground;
  @apply mr-2;
}

.danger-action {
  @apply bg-red-800 hover:bg-red-700 active:bg-red-600;
}

.safe-action {
  @apply bg-green-800 hover:bg-green-700 active:bg-green-600;
}

.qr-container {
  @apply flex flex-col items-center gap-4 p-4;
}

.qr-code {
  @apply bg-white p-4 rounded-lg;
}

.qr-text {
  @apply text-hOnBackground text-center;
}

.download-button {
  @apply flex items-center gap-2 px-4 py-2 rounded-lg;
  @apply bg-hutopyPrimary text-hOnPrimary;
  @apply hover:bg-hutopySecondary;
  @apply transition-colors duration-300;
}

.stripe-status {
  @apply flex flex-row items-center w-full p-3 rounded-lg;
  @apply bg-hSurface;
  @apply cursor-default;
  @apply transition-colors duration-300;
}

.stripe-status .value {
  @apply text-hOnBackground flex-1 text-center;
  @apply flex items-center justify-center;
}

.stripe-status .value.configured {
  @apply text-green-500;
}

.stripe-actions {
  @apply flex items-center gap-2 ml-4;
}

.configure-stripe-button {
  @apply flex items-center justify-center gap-2 px-4 py-2 rounded-lg;
  @apply bg-hutopyPrimary text-hOnPrimary;
  @apply hover:bg-hutopySecondary;
  @apply transition-colors duration-300;
}

.deconfigure-stripe-button {
  @apply flex items-center justify-center gap-2 px-4 py-2 rounded-lg;
  @apply bg-red-600 text-white;
  @apply hover:bg-red-700;
  @apply transition-colors duration-300;
}
</style>

<i18n>
{
  "en": {
    "personalInfo": "Personal Information",
    "fullName": "Full Name",
    "alias": "Alias",
    "email": "Email",
    "changePassword": "Set Password",
    "creatorInfo": "Creator Information",
    "dangerZone": "Danger Zone",
    "dangerZoneWarning": "The actions below can have significant impacts on your creator page. Please proceed with caution.",
    "deleteWarning": "Are you sure you want to delete your creator page? This action cannot be undone.",
    "restoreWarning": "Are you sure you want to restore your creator page? This will make your page visible again.",
    "deleteCreatorPage": "Delete Creator Page",
    "restoreCreatorPage": "Restore Creator Page",
    "stripeAccountId": "Stripe Account ID",
    "socialNetworks": "Social Networks",
    "handle": "Creator Handle",
    "qrCode": "QR Code",
    "qrCodeDescription": "Print this QR code to share your Hutopy with the world! Perfect for business cards, social media, and promotional materials.",
    "downloadQRCode": "Download QR Code",
    "payment-information": "Payment Information",
    "stripeStatus": "Stripe Status",
    "configured": "Configured",
    "notConfigured": "Not Configured",
    "notSet": "Not Set",
    "configureStripe": "Configure Stripe",
    "phoneNumber": "Phone Number",
    "title": "Title",
    "deconfigureStripe": "Remove Stripe"
  },
  "fr": {
    "personalInfo": "Informations Personnelles",
    "fullName": "Nom Complet",
    "alias": "Alias",
    "email": "Email",
    "changePassword": "Définir le mot de passe",
    "creatorInfo": "Informations du Créateur",
    "dangerZone": "Zone de Danger",
    "dangerZoneWarning": "Les actions ci-dessous peuvent avoir des impacts significatifs sur votre page de créateur. Veuillez procéder avec précaution.",
    "deleteWarning": "Êtes-vous sûr de vouloir supprimer votre page de créateur ? Cette action est irréversible.",
    "restoreWarning": "Êtes-vous sûr de vouloir restaurer votre page de créateur ? Cela rendra votre page à nouveau visible.",
    "deleteCreatorPage": "Supprimer la Page Créateur",
    "restoreCreatorPage": "Restaurer la Page Créateur",
    "stripeAccountId": "ID de Compte Stripe",
    "socialNetworks": "Réseaux Sociaux",
    "handle": "Identifiant du créateur",
    "qrCode": "Code QR",
    "qrCodeDescription": "Imprimez ce code QR pour partager votre Hutopy avec le monde ! Parfait pour les cartes de visite, les réseaux sociaux et les supports promotionnels.",
    "downloadQRCode": "Télécharger le Code QR",
    "payment-information": "Informations de Paiement",
    "stripeStatus": "État de Stripe",
    "configured": "Configuré",
    "notConfigured": "Non Configuré",
    "notSet": "Non Défini",
    "configureStripe": "Configurer Stripe",
    "phoneNumber": "Numéro de téléphone",
    "title": "Titre",
    "deconfigureStripe": "Retirer Stripe"
  },
  "es": {
    "personalInfo": "Información Personal",
    "fullName": "Nombre Completo",
    "alias": "Alias",
    "email": "Correo Electrónico",
    "changePassword": "Establecer contraseña",
    "creatorInfo": "Información del Creador",
    "dangerZone": "Zona de Peligro",
    "dangerZoneWarning": "Las acciones a continuación pueden tener impactos significativos en tu página de creador. Por favor, procede con precaución.",
    "deleteWarning": "¿Estás seguro de que quieres eliminar tu página de creador? Esta acción no se puede deshacer.",
    "restoreWarning": "¿Estás seguro de que quieres restaurar tu página de creador? Esto hará que tu página sea visible nuevamente.",
    "deleteCreatorPage": "Eliminar Página de Creador",
    "restoreCreatorPage": "Restaurar Página de Creador",
    "stripeAccountId": "ID de Cuenta Stripe",
    "socialNetworks": "Redes Sociales",
    "handle": "Identificador del creador",
    "qrCode": "Código QR",
    "qrCodeDescription": "¡Imprime este código QR para compartir tu Hutopy con el mundo! Perfecto para tarjetas de presentación, redes sociales y materiales promocionales.",
    "downloadQRCode": "Descargar Código QR",
    "payment-information": "Información de Pago",
    "stripeStatus": "Estado de Stripe",
    "configured": "Configurado",
    "notConfigured": "No Configurado",
    "notSet": "No Establecido",
    "configureStripe": "Configurar Stripe",
    "phoneNumber": "Número de teléfono",
    "title": "Título",
    "deconfigureStripe": "Eliminar Stripe"
  }
}
</i18n>