<template>
  <v-sheet class="bg-surface" :class="layoutClass" height="100%">
    <!-- Side Layouts -->
    <v-row
      v-if="props.layout !== 'card'"
      class="fill-height"
      :class="{ 'flex-row-reverse': props.layout === 'side-right' }"
      no-gutters
    >
      <!-- Illustration Column -->
      <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="props.branding.title" />
        </div>
        <v-sheet
          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="props.announcementBoard.allTabLabel"
            :date-header="props.announcementBoard.dateHeader"
            :empty-text="props.announcementBoard.emptyText"
            :items="props.announcementBoard.items"
            :items-per-page="props.announcementBoard.itemsPerPage"
            :pagination-label="props.announcementBoard.paginationLabel"
            :school-header="props.announcementBoard.schoolHeader"
            :system-announcements="props.announcementBoard.systemAnnouncements"
            :tabs="props.announcementBoard.tabs"
            :title="props.announcementBoard.title"
            :title-header="props.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"
              >
                {{ props.mobileAnnouncement.viewAllText }}
              </v-btn>
            </template>
          </v-banner>
        </div>
        <LoginToolBar
          v-if="props.toolbar.show"
          :locale="props.toolbar.locale"
          :locales="props.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="props.branding.title" />
          </div>
          <LoginHeader
            class="d-none d-sm-block"
            :welcome-description="props.header.welcomeDescription"
            :welcome-text="props.header.welcomeText"
          />
          <LoginForm
            :acc-placeholder="props.form.accPlaceholder"
            :forgot-password-href="props.form.forgotPassword.href"
            :forgot-password-target="props.form.forgotPassword.target"
            :forgot-password-text="props.form.forgotPassword.text"
            :passw-placeholder="props.form.passwPlaceholder"
            :remember-me-label="props.form.rememberMeLabel"
            :remember-storage-key="props.form.rememberStorageKey"
            :submit-text="props.form.submitText"
            @forgot-password="handleForgotPassword"
            @submit="handleLogin"
          >
            <template v-if="props.form.withCaptcha" #verify>
              <LoginVerify
                :captcha="props.form.captcha"
                :captcha-placeholder="props.form.captchaPlaceholder"
                :error-message="props.form.captchaErrorMessage"
                :loading="props.form.captchaLoading"
                :model-value="props.form.captchaValue"
                :refresh-title="props.form.refreshTitle"
                :verified="props.form.captchaVerified"
                :verify-text="props.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() }} {{ props.branding.organization }}
          </div>
        </div>
      </v-col>
    </v-row>

    <!-- Card Layout (Centered) -->
    <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="props.toolbar.show ? 'px-8 pt-0 pb-4' : 'pa-8'"
        elevation="10"
        max-width="450"
        width="100%"
      >
        <LoginToolBar
          v-if="props.toolbar.show"
          :locale="props.toolbar.locale"
          :locales="props.toolbar.locales"
          @change-locale="handleChangeLocale"
          @toggle-layout="handleToggleLayout"
        />
        <div class="d-flex justify-center mb-6 mb-md-4">
          <LoginBrand :title="props.branding.title" />
        </div>
        <LoginHeader
          class="d-none d-md-block"
          :welcome-description="props.header.welcomeDescription"
          :welcome-text="props.header.welcomeText"
        />
        <LoginForm
          :acc-placeholder="props.form.accPlaceholder"
          :forgot-password-href="props.form.forgotPassword.href"
          :forgot-password-target="props.form.forgotPassword.target"
          :forgot-password-text="props.form.forgotPassword.text"
          :passw-placeholder="props.form.passwPlaceholder"
          :remember-me-label="props.form.rememberMeLabel"
          :remember-storage-key="props.form.rememberStorageKey"
          :submit-text="props.form.submitText"
          @forgot-password="handleForgotPassword"
          @submit="handleLogin"
        >
          <template v-if="props.form.withCaptcha" #verify>
            <LoginVerify
              :captcha="props.form.captcha"
              :captcha-placeholder="props.form.captchaPlaceholder"
              :error-message="props.form.captchaErrorMessage"
              :loading="props.form.captchaLoading"
              :model-value="props.form.captchaValue"
              :refresh-title="props.form.refreshTitle"
              :verified="props.form.captchaVerified"
              :verify-text="props.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() }} {{ props.branding.organization }}
        </div>
      </v-card>
    </v-row>

    <v-bottom-sheet v-model="mobileAnnouncementSheetVisible" class="d-sm-none">
      <v-card rounded="t-xl">
        <v-card-title class="text-subtitle-1 font-weight-bold">
          {{ props.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>{{ props.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">
            {{ props.mobileAnnouncement.closeText }}
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-bottom-sheet>
  </v-sheet>
</template>

<script setup lang="ts">
import { mdiBullhornVariantOutline } from '@mdi/js'
import { computed, ref } from 'vue'
import LoginAnnouncementBoard from './login/LoginAnnouncementBoard.vue'
import LoginBrand from './login/LoginBrand.vue'
import LoginForm from './login/LoginForm.vue'
import LoginHeader from './login/LoginHeader.vue'
import LoginToolBar from './login/LoginToolBar.vue'
import LoginVerify from './login/LoginVerify.vue'

interface BrandingConfig {
  title?: string
  organization?: string
}

interface IllustrationConfig {
  image?: string | null
  title?: string
  description?: string
}

interface HeaderConfig {
  welcomeText?: string
  welcomeDescription?: string
}

interface AnnouncementTabConfig {
  label: string
  value: string
}

interface AnnouncementItemConfig {
  id: string | number
  date: string
  school: string
  title: string
  tab?: string
}

interface AnnouncementBoardConfig {
  title?: string
  tabs?: AnnouncementTabConfig[]
  items?: AnnouncementItemConfig[]
  systemAnnouncements?: {
    id: string | number
    content: string
    title?: string
    createdAt?: string
  }[]
  allTabLabel?: string
  itemsPerPage?: number
  dateHeader?: string
  schoolHeader?: string
  titleHeader?: string
  emptyText?: string
  paginationLabel?: string
}

interface MobileAnnouncementConfig {
  items?: {
    id: string | number
    content: string
    title?: string
    createdAt?: string
  }[]
  show?: boolean
  viewAllText?: string
  listTitle?: string
  closeText?: string
  emptyText?: string
}

interface ForgotPasswordConfig {
  text?: string
  href?: string
  target?: string
}

interface FormConfig {
  accPlaceholder?: string
  passwPlaceholder?: string
  rememberMeLabel?: string
  submitText?: string
  rememberStorageKey?: string
  withCaptcha?: boolean
  captcha?: {
    imgUrl?: string
    id?: string
    tokenValue?: string
  }
  captchaValue?: string
  captchaLoading?: boolean
  captchaErrorMessage?: string
  captchaVerified?: boolean
  verifyText?: string
  captchaPlaceholder?: string
  refreshTitle?: string
  forgotPassword: ForgotPasswordConfig
}

interface ToolBarConfig {
  show?: boolean
  locale?: string
  locales?: string[]
}

interface Props {
  layout: 'side-left' | 'side-right' | 'card'
  branding: BrandingConfig
  illustration: IllustrationConfig
  announcementBoard: AnnouncementBoardConfig
  mobileAnnouncement: MobileAnnouncementConfig
  header: HeaderConfig
  form: FormConfig
  toolbar: ToolBarConfig
}

const props = withDefaults(defineProps<Props>(), {
  layout: 'side-left',
  branding: () => ({
    title: 'Skyteck Login',
    organization: 'school',
  }),
  illustration: () => ({
    image: null,
    title: 'Login',
    description: 'Login to your account',
  }),
  announcementBoard: () => ({
    title: '學校公告區',
    tabs: [
      { label: '全部', value: '__all__' },
      { label: '國中', value: 'junior' },
      { label: '高中', value: 'senior' },
    ],
    items: [
      {
        id: 'announcement-1',
        date: '2024-03-19',
        school: '市立實踐國中',
        title: '臺北市立實踐國中徵求113學年度教學支援工作人員',
        tab: 'junior',
      },
    ],
    systemAnnouncements: [],
    allTabLabel: '全部',
    itemsPerPage: 5,
    dateHeader: '公告時間',
    schoolHeader: '公告學校',
    titleHeader: '公告標題',
    emptyText: '目前沒有公告資料',
    paginationLabel: '總筆數：',
  }),
  mobileAnnouncement: () => ({
    items: [],
    show: false,
    viewAllText: '查看全部',
    listTitle: '系統公告',
    closeText: '關閉',
    emptyText: '目前沒有公告',
  }),
  header: () => ({
    welcomeText: 'Welcome back 👋🏻',
    welcomeDescription: 'Please enter your account password to login',
  }),
  form: () => ({
    accPlaceholder: '請輸入帳號',
    passwPlaceholder: '請輸入密碼',
    rememberMeLabel: '記住帳號',
    submitText: '登入',
    rememberStorageKey: 'sklogin.remember.username',
    withCaptcha: true,
    captcha: undefined,
    captchaValue: '',
    captchaLoading: false,
    captchaErrorMessage: '',
    captchaVerified: false,
    verifyText: '驗證',
    captchaPlaceholder: '驗證碼',
    refreshTitle: '點擊刷新驗證碼',
    forgotPassword: {
      text: '忘記密碼?',
      href: '',
      target: undefined,
    },
  }),
  toolbar: () => ({
    show: true,
    locale: 'zh-TW',
    locales: ['zh-TW', 'en-US'],
  }),
})

const emit = defineEmits([
  'submit',
  'change-locale',
  'forgot-password',
  'captcha-refresh',
  'captcha-change',
  'toggle-layout',
  'select-announcement',
])

const mobileAnnouncementSheetVisible = ref(false)

const mobileAnnouncementItems = computed(() => props.mobileAnnouncement.items ?? [])

const showMobileAnnouncementBanner = computed(() => {
  if (props.mobileAnnouncement.show === false) return false
  return mobileAnnouncementItems.value.length > 0
})

const mobileAnnouncementBannerText = computed(() => {
  return mobileAnnouncementItems.value[0]?.content ?? ''
})

const layoutClass = computed(() => {
  return `layout-${props.layout}`
})

function handleLogin(formData: Record<string, unknown>) {
  emit('submit', formData)
}

function handleCaptchaRefresh() {
  emit('captcha-refresh')
}

function handleCaptchaChange(value: string) {
  emit('captcha-change', value)
}

function handleChangeLocale(nextLocale: string) {
  emit('change-locale', nextLocale)
}

function handleToggleLayout() {
  emit('toggle-layout')
}

function handleForgotPassword(e: MouseEvent) {
  emit('forgot-password', e)
}

function handleSelectAnnouncement(item: AnnouncementItemConfig) {
  emit('select-announcement', item)
}
</script>

<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;
}

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