<template>
  <!-- 预约机构：见 doc/app/预约服务/预约服务接口说明.md -->
  <view :class="pageRootClass" class="tab-page bgo-page" :style="pageStyle">
    <scroll-view scroll-y class="bgo-scroll" enable-back-to-top :show-scrollbar="false">
      <view class="bgo-card bgo-card--top">
        <view class="bgo-hero">
          <up-avatar
            v-if="photoSrc"
            shape="circle"
            :src="photoSrc"
            size="72"
            font-size="26"
          />
          <up-avatar
            v-else
            shape="circle"
            :text="avatarText"
            size="72"
            font-size="26"
            bg-color="#9ca3af"
            color="#ffffff"
          />
          <view class="bgo-hero__right">
            <text class="bgo-hero__title text-body">{{ orgTitle }}</text>
            <text class="bgo-hero__sub text-body">{{ orgSub }}</text>
            <text class="bgo-hero__contact text-body">{{ contactLine }}</text>
          </view>
        </view>
        <text class="bgo-line text-body"><text class="bgo-line__k">{{ $t('bookingOrgPage.labelIntro') }}</text>{{ introBody }}</text>
        <text class="bgo-line text-body"><text class="bgo-line__k">{{ $t('bookingOrgPage.labelAddress') }}</text>{{ detailAddress }}</text>
        <text class="bgo-line text-body"><text class="bgo-line__k">{{ $t('bookingOrgPage.labelHours') }}</text>{{ serviceHours }}</text>
      </view>

      <view class="bgo-card bgo-card--bottom">
        <text class="bgo-section-title text-body">{{ $t('bookingOrgPage.pickTimeTitle') }}</text>
        <scroll-view scroll-x class="bgo-date-scroll" :show-scrollbar="false" enable-flex>
          <view class="bgo-date-row">
            <view
              v-for="chip in dateChips"
              :key="chip.key"
              class="bgo-chip"
              :class="{
                'bgo-chip--on': !chip.weekdayDisabled && selectedDateKey === chip.key,
                'bgo-chip--disabled': chip.weekdayDisabled
              }"
              role="button"
              @tap="onChipTap(chip)"
            >
              <view class="bgo-chip__stack">
                <text class="bgo-chip__name text-body">{{ chip.weekdayLabel }}</text>
                <text v-if="!chip.weekdayDisabled" class="bgo-chip__date text-body">{{ chip.dateShort }}</text>
                <text v-else class="bgo-chip__full text-body">{{ $t('bookingOrgPage.dayNotAvailable') }}</text>
              </view>
            </view>
          </view>
        </scroll-view>
        <up-divider :hairline="true" line-color="#e5e7eb" margin="12rpx 0 8rpx" />
        <up-button
          type="success"
          shape="circle"
          :disabled="bookBtnDisabled"
          :text="bookBtnText"
          @click="openBookPopup"
        />
      </view>
      <view class="bgo-footer-spacer" />
    </scroll-view>

    <up-popup
      :show="bookPopupShow"
      mode="center"
      :round="16"
      :close-on-click-overlay="true"
      :safe-area-inset-bottom="true"
      :custom-style="bookPopupStyle"
      @update:show="bookPopupShow = $event"
    >
      <view class="bgo-popup">
        <scroll-view scroll-y class="bgo-popup__scroll" :show-scrollbar="false">
          <text class="bgo-popup__h1 text-body">{{ $t('bookingOrgPage.popupBookTitle') }}</text>
          <text class="bgo-popup__row text-body">{{ $t('bookingOrgPage.popupOrgName') }}{{ orgTitle }}</text>
          <text class="bgo-popup__row text-body">{{ $t('bookingOrgPage.popupBookDate') }}{{ popupDateLine }}</text>

          <text class="bgo-popup__h2 text-body">{{ $t('bookingOrgPage.popupServiceTitle') }}</text>
          <up-form
            ref="bookFormRef"
            label-position="top"
            :model="formModel"
            :rules="formRules"
            label-width="100%"
            :border-bottom="false"
            error-type="toast"
          >
            <up-form-item :label="$t('bookingOrgPage.formBooker')" prop="bookerName" required>
              <up-input v-model="formModel.bookerName" border="surround" clearable />
            </up-form-item>
            <up-form-item :label="$t('bookingOrgPage.formPhone')" prop="phone" required>
              <up-input v-model="formModel.phone" type="number" maxlength="11" border="surround" clearable />
            </up-form-item>
          </up-form>
        </scroll-view>

        <view class="bgo-popup__actions">
          <up-button
            class="bgo-popup__btn bgo-popup__btn--cancel"
            :text="$t('bookingOrgPage.btnCancel')"
            shape="circle"
            plain
            hairline
            @click="closeBookPopup"
          />
          <up-button
            class="bgo-popup__btn"
            type="success"
            :loading="submitting"
            :text="submitting ? $t('bookingOrgPage.submitting') : $t('bookingOrgPage.btnSubmit')"
            shape="circle"
            @click="onSubmitBook"
          />
        </view>
      </view>
    </up-popup>
  </view>
</template>

<script>
import UAvatar from 'uview-plus/components/u-avatar/u-avatar.vue'
import UButton from 'uview-plus/components/u-button/u-button.vue'
import UDivider from 'uview-plus/components/u-divider/u-divider.vue'
import UForm from 'uview-plus/components/u-form/u-form.vue'
import UFormItem from 'uview-plus/components/u-form-item/u-form-item.vue'
import UInput from 'uview-plus/components/u-input/u-input.vue'
import UPopup from 'uview-plus/components/u-popup/u-popup.vue'
import tabPage from '@/mixins/tabPage'
import pageViewport from '@/mixins/pageViewport'
import { resolveResourceUrl } from '@/utils/resourceUrl'
import { ensureApiToken } from '@/utils/apiAuth'
import { useUserStore } from '@/store/user'
import {
  BOOKING_PROVIDER_TYPE,
  checkAppointmentBooked,
  listBookingDates,
  loadBookingResourceCache,
  submitBookingAppointment
} from '@/api/bookingService'

const ORG_RESOURCE_TYPE = '004003'

function parseServiceWeekdays(raw) {
  if (raw == null || String(raw).trim() === '') return null
  const set = new Set()
  for (const part of String(raw).split(',')) {
    const n = parseInt(part.trim(), 10)
    if (n >= 1 && n <= 7) set.add(n)
  }
  return set.size ? set : null
}

export default {
  components: {
    'up-avatar': UAvatar,
    'up-button': UButton,
    'up-divider': UDivider,
    'up-form': UForm,
    'up-form-item': UFormItem,
    'up-input': UInput,
    'up-popup': UPopup
  },
  mixins: [tabPage, pageViewport],
  data() {
    return {
      navTitleKey: 'bookingOrgPage.navTitle',
      orgId: '',
      resourceType: ORG_RESOURCE_TYPE,
      resource: null,
      apiDates: [],
      bookedDateMap: {},
      selectedDateKey: '',
      bookPopupShow: false,
      submitting: false,
      formModel: {
        bookerName: '',
        phone: ''
      },
      bookPopupStyle: {
        width: '90%',
        maxWidth: '680px',
        maxHeight: '72vh',
        overflow: 'hidden',
        display: 'flex',
        flexDirection: 'column'
      }
    }
  },
  computed: {
    allowedWeekdays() {
      return parseServiceWeekdays(this.resource && this.resource.serviceWeekdays)
    },
    dateChips() {
      return (this.apiDates || []).map((d) => {
        const key = d.appointDate || ''
        const weekday = d.weekday
        const allowed = this.allowedWeekdays
        const weekdayDisabled =
          allowed != null && weekday != null && !allowed.has(Number(weekday))
        return {
          key,
          dateShort: d.dateMmDd || '',
          weekday,
          weekdayLabel: this.weekdayLabelFor(d),
          weekdayDisabled
        }
      })
    },
    photoSrc() {
      const url = this.resource && this.resource.photoFileUrl
      return url ? resolveResourceUrl(url) : ''
    },
    selectedDateBooked() {
      return !!this.bookedDateMap[this.selectedDateKey]
    },
    bookBtnDisabled() {
      const chip = this.dateChips.find((c) => c.key === this.selectedDateKey)
      if (!chip || chip.weekdayDisabled) return true
      return this.selectedDateBooked
    },
    bookBtnText() {
      if (this.selectedDateBooked) return this.$t('bookingOrgPage.btnBooked')
      return this.$t('bookingOrgPage.btnBook')
    },
    avatarText() {
      const name = (this.resource && this.resource.resourceName) || ''
      return name.slice(0, 1) || '?'
    },
    orgTitle() {
      return (this.resource && this.resource.resourceName) || this.$t('bookingOrgPage.noResource')
    },
    orgSub() {
      return (this.resource && this.resource.affiliatedUnit) || this.$t('bookingServicePage.noUnit')
    },
    introBody() {
      const intro = (this.resource && this.resource.introduction) || ''
      return intro.trim() || this.$t('bookingOrgPage.noIntro')
    },
    contactLine() {
      const phone = this.resource && this.resource.contactPhone
      if (!phone) return this.$t('bookingOrgPage.contactLabel') + '—'
      return this.$t('bookingOrgPage.contactLabel') + phone
    },
    detailAddress() {
      const addr = (this.resource && this.resource.detailAddress) || ''
      return addr.trim() || this.$t('bookingOrgPage.noAddress')
    },
    serviceHours() {
      const start = this.resource && this.resource.serviceStartTime
      const end = this.resource && this.resource.serviceEndTime
      if (start && end) {
        return this.$t('bookingOrgPage.hoursTpl', { start, end })
      }
      return this.$t('bookingOrgPage.noHours')
    },
    defaultTimeSlot() {
      const start = this.resource && this.resource.serviceStartTime
      const end = this.resource && this.resource.serviceEndTime
      if (start && end) return `${start}~${end}`
      return '08:00~17:00'
    },
    popupDateLine() {
      const chip = this.dateChips.find((c) => c.key === this.selectedDateKey)
      if (!chip || chip.weekdayDisabled) return ''
      return this.formatMdWeekday(chip)
    },
    formRules() {
      return {
        bookerName: [
          {
            required: true,
            message: this.$t('bookingOrgPage.errBooker'),
            trigger: ['blur', 'change']
          }
        ],
        phone: [
          {
            required: true,
            message: this.$t('bookingOrgPage.errPhone'),
            trigger: ['blur', 'change']
          },
          {
            pattern: /^1[3-9]\d{9}$/,
            message: this.$t('bookingOrgPage.errPhoneFmt'),
            trigger: ['blur', 'change']
          }
        ]
      }
    }
  },
  onLoad(query) {
    if (!ensureApiToken()) return
    const q = query || {}
    this.orgId = q.id ? decodeURIComponent(String(q.id)) : ''
    if (q.resourceType) {
      try {
        this.resourceType = decodeURIComponent(String(q.resourceType))
      } catch (e) {
        this.resourceType = String(q.resourceType)
      }
    }
    this.loadResource()
    this.loadBookingDates()
  },
  methods: {
    weekdayLabelFor(d) {
      const w = d && d.weekday
      if (w != null && w >= 1 && w <= 7) {
        const dowKey = w === 7 ? 0 : w
        return this.$t(`bookingServicePage.wd${dowKey}`)
      }
      return (d && d.weekdayName) || ''
    },
    loadResource() {
      if (!this.orgId) {
        uni.showToast({ title: this.$t('bookingOrgPage.noResource'), icon: 'none' })
        setTimeout(() => uni.navigateBack(), 1500)
        return
      }
      this.resource = loadBookingResourceCache(this.resourceType, this.orgId)
      if (!this.resource) {
        uni.showToast({ title: this.$t('bookingOrgPage.noResource'), icon: 'none' })
        setTimeout(() => uni.navigateBack(), 1500)
        return
      }
      if (this.apiDates.length) {
        this.refreshBookedFlags()
      }
    },
    loadBookingDates() {
      listBookingDates()
        .then((res) => {
          this.apiDates = Array.isArray(res.data) ? res.data : []
          this.$nextTick(() => {
            this.ensureValidSelection()
            if (this.orgId) {
              this.refreshBookedFlags()
            }
          })
        })
        .catch(() => {
          this.apiDates = []
        })
    },
    refreshBookedFlags() {
      if (!this.orgId || !this.apiDates.length) return Promise.resolve()
      const providerId = Number(this.orgId) || this.orgId
      const dates = this.apiDates.map((d) => d.appointDate).filter(Boolean)
      return Promise.all(
        dates.map((appointDate) =>
          checkAppointmentBooked({
            providerType: BOOKING_PROVIDER_TYPE.ORG,
            providerId,
            appointDate
          })
            .then((res) => ({
              appointDate,
              booked: !!(res.data && res.data.booked)
            }))
            .catch(() => ({ appointDate, booked: false }))
        )
      ).then((results) => {
        const next = { ...this.bookedDateMap }
        results.forEach(({ appointDate, booked }) => {
          next[appointDate] = booked
        })
        this.bookedDateMap = next
        this.$nextTick(() => this.ensureValidSelection())
      })
    },
    fetchDateBooked(appointDate) {
      if (!this.orgId || !appointDate) return Promise.resolve(false)
      return checkAppointmentBooked({
        providerType: BOOKING_PROVIDER_TYPE.ORG,
        providerId: Number(this.orgId) || this.orgId,
        appointDate
      })
        .then((res) => {
          const booked = !!(res.data && res.data.booked)
          this.bookedDateMap = { ...this.bookedDateMap, [appointDate]: booked }
          return booked
        })
        .catch(() => false)
    },
    formatMdWeekday(chip) {
      if (!chip || !chip.key) return ''
      return `${chip.dateShort}（${chip.weekdayLabel}）`
    },
    ensureValidSelection() {
      const cur = this.dateChips.find((c) => c.key === this.selectedDateKey && !c.weekdayDisabled)
      if (cur) return
      const ok = this.dateChips.find((c) => !c.weekdayDisabled)
      this.selectedDateKey = ok ? ok.key : ''
    },
    onChipTap(chip) {
      if (chip.weekdayDisabled) {
        uni.showToast({
          title: this.$t('bookingOrgPage.dayNotAvailable'),
          icon: 'none'
        })
        return
      }
      this.selectedDateKey = chip.key
      this.fetchDateBooked(chip.key)
    },
    openBookPopup() {
      if (!this.resource || !this.orgId) {
        uni.showToast({ title: this.$t('bookingOrgPage.noResource'), icon: 'none' })
        return
      }
      const sel = this.dateChips.find((c) => c.key === this.selectedDateKey)
      if (!sel || sel.weekdayDisabled) {
        uni.showToast({
          title: this.$t('bookingOrgPage.toastPickDate'),
          icon: 'none'
        })
        return
      }
      if (this.selectedDateBooked) return
      const addr = (this.resource.detailAddress || '').trim()
      if (!addr) {
        uni.showToast({ title: this.$t('bookingOrgPage.noAddress'), icon: 'none' })
        return
      }
      this.resetBookForm()
      this.bookPopupShow = true
    },
    closeBookPopup() {
      this.bookPopupShow = false
    },
    resetBookForm() {
      const store = useUserStore()
      const name = store.displayName()
      this.formModel = {
        bookerName: name || '',
        phone: ''
      }
      this.$nextTick(() => {
        this.$refs.bookFormRef?.clearValidate?.()
      })
    },
    onSubmitBook() {
      if (this.submitting) return
      this.$refs.bookFormRef
        ?.validate?.()
        .then(() => {
          const addr = (this.resource.detailAddress || '').trim()
          if (!addr) {
            uni.showToast({ title: this.$t('bookingOrgPage.noAddress'), icon: 'none' })
            return Promise.reject(new Error('no address'))
          }
          this.submitting = true
          return submitBookingAppointment({
            resourceType: this.resourceType,
            resourceId: Number(this.orgId) || this.orgId,
            appointDate: this.selectedDateKey,
            appointeeName: (this.formModel.bookerName || '').trim(),
            contactPhone: (this.formModel.phone || '').trim(),
            timeSlot: this.defaultTimeSlot,
            serviceAddress: addr
          })
        })
        .then(() => {
          this.bookedDateMap = { ...this.bookedDateMap, [this.selectedDateKey]: true }
          uni.showToast({
            title: this.$t('bookingOrgPage.toastSubmitOk'),
            icon: 'success'
          })
          this.bookPopupShow = false
        })
        .catch((err) => {
          const msg = err && (err.msg || err.message || '')
          if (String(msg).includes('已满')) {
            uni.showToast({ title: this.$t('bookingOrgPage.toastDayFull'), icon: 'none' })
          }
        })
        .finally(() => {
          this.submitting = false
        })
    }
  }
}
</script>

<style lang="scss" scoped>
@import '@/styles/morandi.scss';
@import '@/styles/tab-page.scss';

.bgo-page {
  // display: flex;
  // flex-direction: column;
  min-width: 0;
  width: 100%;
  height: 100%;
  min-height: 100%;
  overflow: hidden;
  box-sizing: border-box;
  background: $morandi-bg-page;
}

.bgo-scroll {
  // flex: 1;
  // min-height: 0;
  // min-width: 0;
  // height: 0;
  height: 100%;
  box-sizing: border-box;
  padding: 20rpx 24rpx 24rpx;
}

.bgo-card {
  background: #ffffff;
  border-radius: 16rpx;
  border: 1rpx solid $morandi-border-soft;
  padding: 24rpx;
  box-sizing: border-box;
}

.bgo-card--top {
  margin-bottom: 10rpx;
}

.bgo-hero {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 20rpx;
  min-width: 0;
  margin-bottom: 20rpx;
}

.bgo-hero__right {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}

.bgo-hero__title {
  font-size: 32rpx;
  font-weight: 600;
  color: #111827;
  line-height: 1.35;
  word-break: break-word;
}

.bgo-hero__sub {
  font-size: 24rpx;
  color: $morandi-text-secondary;
  line-height: 1.45;
  word-break: break-word;
}

.bgo-hero__contact {
  font-size: 22rpx;
  color: $morandi-text-muted;
  line-height: 1.45;
  word-break: break-word;
}

.bgo-line {
  display: block;
  font-size: 24rpx;
  line-height: 1.55;
  color: #111827;
  margin-top: 12rpx;
  word-break: break-word;
}

.bgo-line__k {
  color: $morandi-text-muted;
  margin-right: 4rpx;
}

.bgo-section-title {
  display: block;
  font-size: 28rpx;
  font-weight: 600;
  color: #111827;
  margin-bottom: 16rpx;
}

.bgo-date-scroll {
  width: 100%;
  white-space: nowrap;
}

.bgo-date-row {
  display: inline-flex;
  flex-direction: row;
  align-items: stretch;
  gap: 12rpx;
  padding: 4rpx 0 8rpx;
  min-width: min-content;
}

.bgo-chip {
  flex-shrink: 0;
  min-width: 96rpx;
  padding: 12rpx 16rpx;
  border-radius: 12rpx;
  border: 1rpx solid #e5e7eb;
  background: #ffffff;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}

.bgo-chip--on {
  background: #22c55e;
  border-color: #16a34a;
}

.bgo-chip--disabled {
  opacity: 0.75;
  background: #f9fafb;
  border-color: #e5e7eb;
}

.bgo-chip__stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4rpx;
}

.bgo-chip__name {
  font-size: 24rpx;
  color: #111827;
  font-weight: 500;
}

.bgo-chip__date {
  font-size: 22rpx;
  color: #374151;
}

.bgo-chip__full {
  font-size: 22rpx;
  color: #9ca3af;
  font-weight: 500;
}

.bgo-chip--on .bgo-chip__name,
.bgo-chip--on .bgo-chip__date {
  color: #ffffff;
  font-weight: 600;
}

.bgo-chip--disabled .bgo-chip__name {
  color: #9ca3af;
}

.bgo-footer-spacer {
  height: 32rpx;
}

.bgo-popup {
  display: flex;
  flex-direction: column;
  min-width: 0;
  max-height: 72vh;
  padding: 24rpx 24rpx 16rpx;
  box-sizing: border-box;
}

.bgo-popup__scroll {
  flex: 1;
  min-height: 0;
  max-height: 48vh;
}

.bgo-popup__h1 {
  display: block;
  font-size: 30rpx;
  font-weight: 600;
  color: #111827;
  margin-bottom: 20rpx;
}

.bgo-popup__h2 {
  display: block;
  font-size: 28rpx;
  font-weight: 600;
  color: #111827;
  margin: 24rpx 0 16rpx;
}

.bgo-popup__row {
  display: block;
  font-size: 26rpx;
  color: #374151;
  line-height: 1.5;
  margin-bottom: 8rpx;
  word-break: break-word;
}

.bgo-popup__actions {
  display: flex;
  flex-direction: row;
  gap: 20rpx;
  padding-top: 16rpx;
  border-top: 1rpx solid #e5e7eb;
  margin-top: 8rpx;
}

.bgo-popup__btn {
  flex: 1;
  min-width: 0;
}

.bgo-popup__btn--cancel {
  background: #ffffff !important;
}

.bgo-page.lang-bo {
  .bgo-hero__title {
    font-size: 28rpx;
    line-height: 1.75;
  }
}
</style>
