<script setup lang="ts">
import { mdiBullhornVariantOutline } from '@mdi/js'
import { computed, onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import HyakkaouAcademyImage from '@/assets/logo.png'
import LoginAnnouncementBoard from '@/components/login/LoginAnnouncementBoard.vue'
import LoginBrand from '@/components/login/LoginBrand.vue'
import LoginForm from '@/components/login/LoginForm.vue'
import LoginHeader from '@/components/login/LoginHeader.vue'
import LoginToolBar from '@/components/login/LoginToolBar.vue'
import LoginVerify from '@/components/login/LoginVerify.vue'
import {
  type LoginAnnouncementListItem,
  useLoginAnnouncements,
} from '@/composables/useLoginAnnouncements'
import { useLoginCaptcha } from '@/composables/useLoginCaptcha'
import { useAuthStore } from '@/stores/auth'
import { useMenuStore } from '@/stores/menu'
import { useSnackbarStore } from '@/stores/snackbar'

type LayoutType = 'side-left' | 'side-right' | 'card'

const { t, locale } = useI18n()
const router = useRouter()
const route = useRoute()
const authStore = useAuthStore()
const menuStore = useMenuStore()
const snackbarStore = useSnackbarStore()

const locales = ['zh-TW', 'en-US']
const illustrationImage = ref(HyakkaouAcademyImage)
const formPositionLayout = ref<LayoutType>('side-left')
const withAnnouncement = ref(true)
const withForgotPassword = ref(true)
const withRememberAccount = ref(true)
const withCaptcha = ref(true)

const loginCaptcha = useLoginCaptcha({ enabled: withCaptcha })
const loginAnnouncements = useLoginAnnouncements({ enabled: withAnnouncement })
const {
  boardConfig: announcementBoard,
  mobileAnnouncementConfig: mobileAnnouncement,
  selectedAnnouncement,
  selectedAnnouncementDetail,
} = loginAnnouncements

const title = computed(() => t('pages.login.title'))
const organization = computed(() => t('pages.login.organization'))
const accPlaceholder = computed(() => t('pages.login.accPlaceholder'))
const passwPlaceholder = computed(() => t('pages.login.passwPlaceholder'))
const illustrationTitle = computed(() => t('pages.login.illustrationTitle'))
const illustrationDescription = computed(() => t('pages.login.illustrationDescription'))
const welcomeText = computed(() => t('pages.login.welcomeText'))
const welcomeDescription = computed(() => t('pages.login.welcomeDescription'))
const rememberMeLabel = computed(() => t('pages.login.rememberMeLabel'))
const forgotPasswordText = computed(() => t('pages.login.forgotPasswordText'))
const submitText = computed(() => t('pages.login.submitText'))
const verifyText = computed(() => t('pages.login.verifyText'))
const captchaPlaceholder = computed(() => t('pages.login.captchaPlaceholder'))
const refreshTitle = computed(() => t('pages.login.refreshTitle'))

const forgotPasswordHref = ref('/forgot-password')
const forgotPasswordTarget = ref<string | undefined>(undefined)
const rememberStorageKey = ref('login.remember.username')
const dialogVisible = ref(false)
const dialogTitle = ref('')
const dialogMessage = ref('')
const announcementDialogVisible = ref(false)

const branding = computed(() => ({
  title: title.value,
  organization: organization.value,
}))

const illustration = computed(() => ({
  image: illustrationImage.value,
  title: illustrationTitle.value,
  description: illustrationDescription.value,
}))

const header = computed(() => ({
  welcomeText: welcomeText.value,
  welcomeDescription: welcomeDescription.value,
}))

const form = computed(() => ({
  accPlaceholder: accPlaceholder.value,
  passwPlaceholder: passwPlaceholder.value,
  rememberMeLabel: rememberMeLabel.value,
  submitText: submitText.value,
  verifyText: verifyText.value,
  captchaPlaceholder: captchaPlaceholder.value,
  refreshTitle: refreshTitle.value,
  rememberStorageKey: rememberStorageKey.value,
  withForgotPassword: withForgotPassword.value,
  withRememberAccount: withRememberAccount.value,
  withCaptcha: withCaptcha.value,
  captcha: loginCaptcha.formCaptcha.value,
  captchaValue: loginCaptcha.captchaValue.value,
  captchaLoading: loginCaptcha.captchaLoading.value,
  captchaErrorMessage: loginCaptcha.captchaErrorMessage.value ?? '',
  captchaVerified: false,
  forgotPassword: {
    text: forgotPasswordText.value,
    href: forgotPasswordHref.value,
    target: forgotPasswordTarget.value,
  },
}))

const toolbar = computed(() => ({
  show: true,
  locale: locale.value,
  locales,
}))

const mobileAnnouncementSheetVisible = ref(false)
const mobileAnnouncementItems = computed(() => mobileAnnouncement.value.items ?? [])
const showMobileAnnouncementBanner = computed(() => {
  if (!withAnnouncement.value) return false
  if (mobileAnnouncement.value.show === false) return false
  return mobileAnnouncementItems.value.length > 0
})
const mobileAnnouncementBannerText = computed(() => {
  return mobileAnnouncementItems.value[0]?.content ?? ''
})
const layoutClass = computed(() => `layout-${formPositionLayout.value}`)

function handleForgotPassword(e: MouseEvent) {
  if (!withForgotPassword.value) return
  console.log('Forgot Password Click:', e)
}

function handleChangeLocale(nextLocale: string) {
  locale.value = nextLocale
  localStorage.setItem('locale', nextLocale)
}

async function handleCaptchaRefresh() {
  await loginCaptcha.refreshCaptcha().catch(() => undefined)
}

function handleCaptchaChange(value: string) {
  loginCaptcha.setCaptchaValue(value)
}

function handleToggleLayout() {
  const layoutOrder: LayoutType[] = ['side-left', 'side-right', 'card']
  const currentIndex = layoutOrder.indexOf(formPositionLayout.value)
  const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % layoutOrder.length
  formPositionLayout.value = layoutOrder[nextIndex] ?? 'side-left'
}

function handleSelectAnnouncement(item: LoginAnnouncementListItem) {
  loginAnnouncements.selectById(item.id)
  announcementDialogVisible.value = true
}

async function onLogin(data: Record<string, unknown>) {
  if (withCaptcha.value && !loginCaptcha.captchaValue.value) {
    dialogTitle.value = t('common.notice')
    dialogMessage.value = t('pages.login.alert.verifyRequired')
    dialogVisible.value = true
    return
  }

  try {
    dialogTitle.value = t('common.notice')

    const inputUserId = String(data.username ?? '').trim()
    const inputPassword = String(data.password ?? '').trim()
    const isDev = import.meta.env.DEV
    const devDefaultUserId = String(import.meta.env.VITE_DEV_DEFAULT_USER_ID ?? '').trim()
    const devDefaultPassword = String(import.meta.env.VITE_DEV_DEFAULT_PASSWORD ?? '').trim()
    const userId = isDev && !inputUserId ? devDefaultUserId : inputUserId
    const password = isDev && !inputPassword ? devDefaultPassword : inputPassword

    await authStore.login({
      UserID: userId,
      Password: password,
      captcha: loginCaptcha.getLoginCaptchaPayload(),
    })

    menuStore.getMenu(authStore.user?.id ?? '')

    snackbarStore.show({
      message: t('pages.login.alert.loginSuccess'),
      color: 'success',
      timeout: 2000,
      location: 'top right',
      variant: 'flat',
    })

    const redirect = (route.query.redirect as string) || '/'
    await router.push(redirect.startsWith('/') ? redirect : '/')
  } catch (error) {
    console.error('Login error:', error)
    dialogTitle.value = t('common.notice')
    dialogMessage.value = t('pages.login.alert.loginFailed')
    dialogVisible.value = true
  }
}

onMounted(() => {
  void loginAnnouncements.load()
  void loginCaptcha.loadCaptcha().catch(() => undefined)
})
</script>

<template>
  <v-sheet class="bg-surface" :class="layoutClass" height="100%">
    <v-row
      v-if="formPositionLayout !== 'card'"
      class="fill-height"
      :class="{ 'flex-row-reverse': formPositionLayout === 'side-right' }"
      no-gutters
    >
      <v-col
        class="illustration-panel d-none d-sm-flex align-center justify-center position-relative flex-grow-1"
        cols="12"
        lg="8"
        sm="6"
      >
        <div class="brand-header position-absolute top-0 left-0 px-2 pt-4 pa-lg-4">
          <LoginBrand :title="branding.title" />
        </div>
        <v-sheet
          v-if="withAnnouncement"
          class="board-wrapper pa-2 pa-lg-0"
          color="rgba(var(--v-theme-surface), 0.8)"
          elevation="0"
          max-width="680"
          rounded="lg"
          width="100%"
        >
          <LoginAnnouncementBoard
            :all-tab-label="announcementBoard.allTabLabel"
            :date-header="announcementBoard.dateHeader"
            :empty-text="announcementBoard.emptyText"
            :items="announcementBoard.items"
            :items-per-page="announcementBoard.itemsPerPage"
            :pagination-label="announcementBoard.paginationLabel"
            :school-header="announcementBoard.schoolHeader"
            :system-announcements="announcementBoard.systemAnnouncements"
            :tabs="announcementBoard.tabs"
            :title="announcementBoard.title"
            :title-header="announcementBoard.titleHeader"
            @select-announcement="handleSelectAnnouncement"
          />
        </v-sheet>
      </v-col>

      <v-col
        class="bg-background d-flex flex-column flex-grow-1 px-4 py-2 py-md-0"
        cols="12"
        lg="4"
        sm="6"
      >
        <div v-if="showMobileAnnouncementBanner" class="banner-wrapper px-3">
          <v-banner
            class="d-sm-none mb-2"
            density="comfortable"
            lines="one"
            :mobile="false"
            :stacked="false"
          >
            <template #prepend>
              <v-slide-x-transition appear>
                <div class="mobile-banner-icon-wrap d-flex align-center">
                  <v-icon
                    class="mobile-banner-icon"
                    color="primary"
                    size="small"
                    :icon="mdiBullhornVariantOutline"
                  />
                </div>
              </v-slide-x-transition>
            </template>
            <v-banner-text>{{ mobileAnnouncementBannerText }}</v-banner-text>
            <template #actions>
              <v-btn
                class="text-none"
                color="primary"
                size="small"
                variant="text"
                @click="mobileAnnouncementSheetVisible = true"
              >
                {{ mobileAnnouncement.viewAllText }}
              </v-btn>
            </template>
          </v-banner>
        </div>
        <LoginToolBar
          v-if="toolbar.show"
          :locale="toolbar.locale"
          :locales="toolbar.locales"
          @change-locale="handleChangeLocale"
          @toggle-layout="handleToggleLayout"
        />
        <div
          class="login-form-wrapper d-flex flex-column justify-center py-0 py-sm-4 py-lg-8 px-4 px-sm-6 px-lg-12 flex-grow-1"
        >
          <div class="login-header-height d-flex d-sm-none justify-center align-start">
            <LoginBrand :title="branding.title" />
          </div>
          <LoginHeader
            class="d-none d-sm-block"
            :welcome-description="header.welcomeDescription"
            :welcome-text="header.welcomeText"
          />
          <LoginForm
            :acc-placeholder="form.accPlaceholder"
            :forgot-password-href="form.forgotPassword.href"
            :forgot-password-target="form.forgotPassword.target"
            :forgot-password-text="form.forgotPassword.text"
            :passw-placeholder="form.passwPlaceholder"
            :remember-me-label="form.rememberMeLabel"
            :remember-storage-key="form.rememberStorageKey"
            :submit-text="form.submitText"
            :with-forgot-password="form.withForgotPassword"
            :with-remember-account="form.withRememberAccount"
            @forgot-password="handleForgotPassword"
            @submit="onLogin"
          >
            <template v-if="form.withCaptcha" #verify>
              <LoginVerify
                :captcha="form.captcha"
                :captcha-placeholder="form.captchaPlaceholder"
                :error-message="form.captchaErrorMessage"
                :loading="form.captchaLoading"
                :model-value="form.captchaValue"
                :refresh-title="form.refreshTitle"
                :verified="form.captchaVerified"
                :verify-text="form.verifyText"
                @refresh="handleCaptchaRefresh"
                @update:model-value="handleCaptchaChange"
              />
            </template>
          </LoginForm>
          <div class="mt-auto py-8 text-center text-caption text-grey-darken-2">
            Copyright © {{ new Date().getFullYear() }} {{ branding.organization }}
          </div>
        </div>
      </v-col>
    </v-row>

    <v-row
      v-else
      class="fill-height align-center justify-center bg-background pa-4 pa-md-0"
      no-gutters
    >
      <v-card
        class="rounded-lg"
        :class="toolbar.show ? 'px-8 pt-0 pb-4' : 'pa-8'"
        elevation="10"
        max-width="450"
        width="100%"
      >
        <LoginToolBar
          v-if="toolbar.show"
          :locale="toolbar.locale"
          :locales="toolbar.locales"
          @change-locale="handleChangeLocale"
          @toggle-layout="handleToggleLayout"
        />
        <div class="d-flex justify-center mb-6 mb-md-4">
          <LoginBrand :title="branding.title" />
        </div>
        <LoginHeader
          class="d-none d-md-block"
          :welcome-description="header.welcomeDescription"
          :welcome-text="header.welcomeText"
        />
        <LoginForm
          :acc-placeholder="form.accPlaceholder"
          :forgot-password-href="form.forgotPassword.href"
          :forgot-password-target="form.forgotPassword.target"
          :forgot-password-text="form.forgotPassword.text"
          :passw-placeholder="form.passwPlaceholder"
          :remember-me-label="form.rememberMeLabel"
          :remember-storage-key="form.rememberStorageKey"
          :submit-text="form.submitText"
          :with-forgot-password="form.withForgotPassword"
          :with-remember-account="form.withRememberAccount"
          @forgot-password="handleForgotPassword"
          @submit="onLogin"
        >
          <template v-if="form.withCaptcha" #verify>
            <LoginVerify
              :captcha="form.captcha"
              :captcha-placeholder="form.captchaPlaceholder"
              :error-message="form.captchaErrorMessage"
              :loading="form.captchaLoading"
              :model-value="form.captchaValue"
              :refresh-title="form.refreshTitle"
              :verified="form.captchaVerified"
              :verify-text="form.verifyText"
              @refresh="handleCaptchaRefresh"
              @update:model-value="handleCaptchaChange"
            />
          </template>
        </LoginForm>
        <div class="mt-8 text-center text-caption text-grey-darken-2">
          Copyright © {{ new Date().getFullYear() }} {{ branding.organization }}
        </div>
      </v-card>
    </v-row>

    <v-bottom-sheet
      v-if="withAnnouncement"
      v-model="mobileAnnouncementSheetVisible"
      class="d-sm-none"
    >
      <v-card rounded="t-xl">
        <v-card-title class="text-subtitle-1 font-weight-bold">
          {{ mobileAnnouncement.listTitle }}
        </v-card-title>
        <v-list lines="two">
          <v-list-item v-for="item in mobileAnnouncementItems" :key="item.id">
            <v-list-item-title>{{ item.content }}</v-list-item-title>
            <v-list-item-subtitle v-if="item.title || item.createdAt">
              {{ item.title }}<span v-if="item.title && item.createdAt"> ・ </span
              >{{ item.createdAt }}
            </v-list-item-subtitle>
          </v-list-item>
          <v-list-item v-if="mobileAnnouncementItems.length === 0">
            <v-list-item-title>{{ mobileAnnouncement.emptyText }}</v-list-item-title>
          </v-list-item>
        </v-list>
        <v-card-actions class="justify-end">
          <v-btn color="primary" variant="text" @click="mobileAnnouncementSheetVisible = false">
            {{ mobileAnnouncement.closeText }}
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-bottom-sheet>
  </v-sheet>

  <v-dialog v-model="dialogVisible" width="360">
    <v-card>
      <v-card-title>{{ dialogTitle }}</v-card-title>
      <v-card-text>{{ dialogMessage }}</v-card-text>
      <v-card-actions>
        <v-spacer />
        <v-btn color="primary" variant="flat" @click="dialogVisible = false">
          {{ t('common.ok') }}
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>

  <v-dialog v-model="announcementDialogVisible" max-width="720">
    <v-card>
      <v-card-title class="text-h6">
        {{ selectedAnnouncement?.title }}
      </v-card-title>
      <v-card-subtitle class="pt-2">
        {{ selectedAnnouncement?.date }} ・ {{ selectedAnnouncement?.school }}
      </v-card-subtitle>
      <v-card-text class="text-body-1">
        {{ selectedAnnouncementDetail }}
      </v-card-text>
      <v-card-actions>
        <v-spacer />
        <v-btn color="primary" variant="flat" @click="announcementDialogVisible = false">
          關閉
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<style scoped>
:deep(.v-banner__prepend) {
  align-self: center;
  margin-inline-end: 16px;
}

:deep(.v-banner-actions) {
  align-self: center;
}

.mobile-banner-icon {
  animation: mobile-banner-breathe 2.8s ease-in-out infinite;
  transform-origin: center;
}

@keyframes mobile-banner-breathe {
  0%,
  100% {
    opacity: 0.9;
    transform: scale(1);
  }

  50% {
    opacity: 1;
    transform: scale(1.08);
  }
}

@media (prefers-reduced-motion: reduce) {
  .mobile-banner-icon {
    animation: none;
  }
}

.illustration-panel {
  background: linear-gradient(
    135deg,
    rgb(var(--v-theme-background)) 0%,
    rgb(var(--v-theme-surface)) 100%
  );
  border-right: 1px solid rgba(var(--v-theme-on-surface), 0.05);
}

.login-form-wrapper {
  max-width: 450px;
  margin: 0 auto;
  width: 100%;
}

.login-header-height {
  height: 120px;
}

.layout-side-right .illustration-panel {
  border-right: none;
  border-left: 1px solid rgba(var(--v-theme-on-surface), 0.05);
}
</style>
