<template>
  <div class="relative cst-book-min-cont-hei bookaro-bookings-view">
    <!-- Global Loading Overlay -->
    <!-- Header -->
    <div class="flex items-center justify-between mb-3">
      <div class="flex items-center space-x-3">
        <span class="bookaro-status-chip" data-status="info">
          {{ i18n.total_bookings }} ({{ bookings.length }})
        </span>
      </div>
    </div>

    <div v-if="loading" class="bookaro-loading-shell">
      <div class="bookaro-skeleton-card">
        <div class="bookaro-skeleton bookaro-skeleton-line is-wide"></div>
        <div class="bookaro-skeleton bookaro-skeleton-line is-medium"></div>
        <div class="bookaro-skeleton bookaro-skeleton-line is-short"></div>
      </div>
      <div class="bookaro-skeleton-card">
        <div class="bookaro-skeleton bookaro-skeleton-line is-wide"></div>
        <div class="bookaro-skeleton bookaro-skeleton-line"></div>
        <div class="bookaro-skeleton bookaro-skeleton-line"></div>
        <div class="bookaro-skeleton bookaro-skeleton-line is-medium"></div>
      </div>
    </div>

    <template v-else>
    <!-- Filters -->
    <div class="bookaro-filter-bar mb-6">
      <input
          v-model="filter.service"
          :placeholder="i18n.service_name"
          class="bookaro-input w-full sm:flex-1 sm:min-w-[150px]"
      />
      <input
          v-model="filter.provider"
          :placeholder="i18n.provider_name"
          class="bookaro-input w-full sm:flex-1 sm:min-w-[150px]"
      />
      <div class="relative">
        <button
            @click="showDatepicker = !showDatepicker"
            class="bookaro-btn bookaro-btn--outline"
        >
          {{ filter.date || i18n.select_date }}
        </button>
        <div
            v-if="showDatepicker"
            class="absolute bg-white p-4 mt-2 rounded-lg shadow-lg z-20 filt-cal"
        >
          <DatePicker
              :model-value="filter.date"
              :i18n="i18n"
              @update:modelValue="onDateSelect"
          />
        </div>
      </div>
      <select
          v-model="filter.status"
          class="bookaro-select w-full sm:w-auto sm:min-w-[150px]"
      >
        <option value="">{{ i18n.all_status }}</option>
        <option value="pending">{{ i18n.pending }}</option>
        <option value="approved">{{ i18n.approved }}</option>
        <option value="completed">{{ i18n.completed }}</option>
        <option value="no_show">{{ i18n.no_show }}</option>
        <option value="rejected">{{ i18n.rejected }}</option>
        <option value="cancelled">{{ i18n.cancelled }}</option>
      </select>
      <button @click="clearFilters" class="bookaro-btn bookaro-btn--danger">
        {{ i18n.clear }}
      </button>
      <button @click="fetchBookings" class="bookaro-btn bookaro-btn--outline">
        {{ i18n.refresh }}
      </button>
    </div>

    <div v-if="showFirstRunEmptyState" class="bookaro-card bookaro-card__body mb-6">
      <h3 class="text-base font-semibold text-gray-900">
        {{ firstRunTitle }}
      </h3>
      <p class="mt-1 text-sm text-gray-600">
        {{ firstRunDescription }}
      </p>
      <div class="mt-3 flex flex-wrap gap-2">
        <a
          v-if="browseUrl"
          :href="browseUrl"
          class="bookaro-btn bookaro-btn--primary"
        >
          {{ i18n.empty_action_start_booking || i18n.setup_action_browse || i18n.empty_action_browse_site }}
        </a>
      </div>
    </div>

    <CancelBookingModal
        :show="showCancelModal"
        :booking="cancelBookingTarget"
        :i18n="i18n"
        @close="closeCancelModal"
        @cancelled="handleCancelled"
    />

    <RescheduleModal
        :show="showRescheduleModal"
        :booking="rescheduleBooking"
        :i18n="i18n"
        @close="closeRescheduleModal"
        @rescheduled="handleRescheduled"
    />

    <div class="bookaro-booking-cards">
      <div
        v-for="b in paginatedBookings"
        :key="`card-${b.id}`"
        class="bookaro-booking-card"
      >
        <div class="bookaro-booking-card__header">
          <div>
            <div class="text-sm font-semibold text-gray-900">
              {{ b.service_label || i18n.placeholder_dash }}
            </div>
            <div class="bookaro-booking-card__meta">
              {{ formatDate(b.booking_date) }}
              <span v-if="showDateToColumn && b.booking_date_to">
                &ndash; {{ formatDate(b.booking_date_to) }}
              </span>
            </div>
          </div>
          <span class="bookaro-status-chip" :data-status="b.status">
            {{ statusLabel(b.status) }}
          </span>
        </div>
        <div class="bookaro-booking-card__meta-grid">
          <div class="bookaro-booking-card__meta">
            {{ b.provider_name || i18n.placeholder_dash }}
          </div>
          <div class="bookaro-booking-card__meta">
            {{ i18n.price_label }}:
            {{ b.price_formatted || formatPrice(b.price) }}
          </div>
          <div
            v-if="b.notes"
            class="bookaro-booking-card__meta bookaro-booking-card__meta--full"
          >
            {{ i18n.notes }}: {{ b.notes }}
          </div>
        </div>
        <div class="bookaro-booking-card__actions">
          <button
            @click="viewBooking(b)"
            class="bookaro-btn bookaro-btn--action-view bookaro-btn--sm"
          >
            <ActionIcon name="view" />
            <span>{{ i18n.view }}</span>
          </button>
          <button
            v-if="canCancel(b)"
            @click="cancel(b)"
            :disabled="actionLoading[b.id]"
            class="bookaro-btn bookaro-btn--action-cancel bookaro-btn--sm"
          >
            <ActionIcon name="cancel" />
            <span>{{ i18n.cancel }}</span>
          </button>
          <button
            v-if="canReschedule(b)"
            @click="openReschedule(b)"
            class="bookaro-btn bookaro-btn--action-reschedule bookaro-btn--sm"
          >
            <ActionIcon name="reschedule" />
            <span>{{ i18n.reschedule }}</span>
          </button>
        </div>
      </div>
      <div v-if="showFilteredEmptyState" class="text-sm text-gray-500">
        {{ i18n.empty_filtered_results || i18n.no_bookings }}
      </div>
    </div>

    <!-- Table -->
    <div class="bookaro-table-wrapper overflow-x-auto">
      <table class="bookaro-table">
        <thead>
        <tr>
          <th @click="sortBy('service_label')" class="text-left cursor-pointer whitespace-nowrap">
            {{ i18n.service_name }}
            <span v-if="sortKey==='service_label'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th @click="sortBy('provider_name')" class="text-left cursor-pointer whitespace-nowrap">
            {{ i18n.provider_name }}
            <span v-if="sortKey==='provider_name'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th @click="sortBy('created_at')" class="text-left cursor-pointer whitespace-nowrap">
            {{ i18n.created }}
            <span v-if="sortKey==='created_at'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th @click="sortBy('booking_date')" class="text-left cursor-pointer whitespace-nowrap">
            {{ i18n.date }}
            <span v-if="sortKey==='booking_date'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th
            v-if="showDateToColumn"
            @click="sortBy('booking_date_to')"
            class="text-left cursor-pointer whitespace-nowrap"
          >
            {{ i18n.date_to }}
            <span v-if="sortKey==='booking_date_to'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th @click="sortBy('price')" class="text-left cursor-pointer whitespace-nowrap">
            {{ i18n.price_label }}
            <span v-if="sortKey==='price'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th @click="sortBy('notes')" class="text-left cursor-pointer whitespace-nowrap">
            {{ i18n.notes }}
            <span v-if="sortKey==='notes'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th @click="sortBy('status')" class="text-left cursor-pointer whitespace-nowrap">
            {{ i18n.status }}
            <span v-if="sortKey==='status'">{{ sortAsc?'▲':'▼' }}</span>
          </th>
          <th class="text-left">{{ i18n.actions }}</th>
        </tr>
        </thead>
        <tbody>
        <tr
            v-for="b in paginatedBookings"
            :key="b.id"
            @touchstart="rowTouchStart"
            @touchend="rowTouchEnd(b, $event)"
        >
          <td>
            {{ b.service_label || i18n.placeholder_dash }}
          </td>
          <td>
            {{ b.provider_name || i18n.placeholder_dash }}
          </td>
          <td>{{ formatDate(b.created_at) }}</td>
          <td>{{ formatDate(b.booking_date) }}</td>
          <td v-if="showDateToColumn">{{ b.booking_date_to ? formatDate(b.booking_date_to) : i18n.placeholder_dash }}</td>
          <td>{{ b.price_formatted || formatPrice(b.price) }}</td>
          <td>{{ b.notes || i18n.placeholder_dash }}</td>
          <td>
            <div class="status-stack">
              <div class="status-row">
                <span class="status-label">{{ i18n.booking_status_label || i18n.status }}</span>
                <span class="bookaro-status-chip" :data-status="b.status">
                  {{ statusLabel(b.status) }}
                </span>
              </div>
            </div>
          </td>
          <td class="bookaro-table-actions-cell">
            <div class="bookaro-table-actions">
              <ActionsMenu
                v-if="isCompact"
                :items="actionMenuItems(b)"
                :label="i18n.actions"
              />
              <template v-else>
              <button
                  @click="viewBooking(b)"
                  class="bookaro-btn bookaro-btn--action-view bookaro-btn--sm"
              >
                <ActionIcon name="view" />
                <span>{{ i18n.view }}</span>
              </button>
              <button
                  v-if="canCancel(b)"
                  @click="cancel(b)"
                  :disabled="actionLoading[b.id]"
                  class="bookaro-btn bookaro-btn--action-cancel bookaro-btn--sm"
              >
                <template v-if="actionLoading[b.id]">
                  <span class="loader-button mr-1"></span>
                </template>
                <template v-else>
                  <ActionIcon name="cancel" />
                  <span>{{ i18n.cancel }}</span>
                </template>
              </button>
              <button
                  v-if="canReschedule(b)"
                  @click="openReschedule(b)"
                  class="bookaro-btn bookaro-btn--action-reschedule bookaro-btn--sm"
              >
                <ActionIcon name="reschedule" />
                <span>{{ i18n.reschedule }}</span>
              </button>
              </template>
            </div>
          </td>
        </tr>
        <tr v-if="showFilteredEmptyState">
          <td :colspan="showDateToColumn ? 9 : 8" class="text-center py-4 text-gray-500">
            {{ i18n.empty_filtered_results || i18n.no_bookings }}
          </td>
        </tr>
        </tbody>
      </table>
    </div>

    <!-- Pagination -->
    <div class="flex flex-col sm:flex-row items-start sm:items-center justify-between mt-3 gap-4">
      <div class="flex items-center space-x-2">
        <label class="text-sm font-medium">{{ i18n.show }}</label>
        <select v-model="pageSize" class="bookaro-select">
          <option v-for="n in pageSizes" :key="n" :value="n">{{ n }}</option>
        </select>
        <span class="text-sm">{{ i18n.entries }}</span>
      </div>
      <div class="flex items-center space-x-2">
        <button @click="currentPage=1" :disabled="currentPage===1" class="bookaro-btn bookaro-btn--primary hidden lg:inline-flex">
          &laquo; {{ i18n.first }}
        </button>
        <button @click="currentPage--" :disabled="currentPage===1" class="bookaro-btn bookaro-btn--primary">
          &lsaquo; {{ i18n.prev }}
        </button>
        <span class="text-sm font-medium">
          {{ i18n.page }} {{ currentPage }} {{ i18n.of }} {{ totalPages }}
        </span>
        <button @click="currentPage++" :disabled="currentPage===totalPages" class="bookaro-btn bookaro-btn--primary">
          {{ i18n.next }} &rsaquo;
        </button>
        <button @click="currentPage=totalPages" :disabled="currentPage===totalPages" class="bookaro-btn bookaro-btn--primary hidden lg:inline-flex">
          {{ i18n.last }} &raquo;
        </button>
      </div>
    </div>
    </template>
  </div>
</template>
<script>
import { restRequest } from '@bookaro-free/js/rest';
import CancelBookingModal from '@bookaro-free/components/modals/CancelBookingModal.vue';
import DatePicker from '@bookaro-free/components/DatePicker.vue';
import RescheduleModal from '@bookaro-free/components/modals/RescheduleModal.vue';
import ActionIcon from '@bookaro-free/components/ActionIcon.vue';
import ActionsMenu from '@bookaro-free/components/dashboard/ActionsMenu.vue';


export default {
  name: 'OwnerBookingsView',
  components: { CancelBookingModal, DatePicker, RescheduleModal, ActionIcon, ActionsMenu },
  props: {
    i18n: { type: Object, required: true }
  },
  data() {
    return {
      bookings: [],
      loading: true,
      filter: { service: '', provider: '', date: '', status: '' },
      showDatepicker: false,
      sortKey: 'created_at',
      sortAsc: false,
      pageSizes: [5, 10, 25, 50],
      pageSize: 10,
      currentPage: 1,
      actionLoading: {},
      showCancelModal: false,
      cancelBookingTarget: null,
      touchStartX: 0,
      touchStartY: 0,
      showRescheduleModal: false,
      rescheduleBooking: null,
    };
  },
  computed: {
    isCompact() {
      return (window.BookaroData?.dashboard_density || '') === 'compact';
    },
    setupData() {
      return window.BookaroData?.setup || null;
    },
    browseUrl() {
      return this.setupData?.browse_url || '';
    },
    isPro() {
      return !!window.BookaroData?.is_pro;
    },
    hasActiveFilters() {
      return !!(
        this.filter.service ||
        this.filter.provider ||
        this.filter.date ||
        this.filter.status
      );
    },
    showFirstRunEmptyState() {
      return !this.loading && this.bookings.length === 0 && !this.hasActiveFilters;
    },
    showFilteredEmptyState() {
      return !this.loading && this.paginatedBookings.length === 0 && !this.showFirstRunEmptyState;
    },
    firstRunTitle() {
      return this.i18n.empty_customer_bookings_title || this.i18n.setup_owner_title || this.i18n.no_bookings;
    },
    firstRunDescription() {
      if (this.isPro && this.i18n.empty_customer_bookings_desc_pro) {
        return this.i18n.empty_customer_bookings_desc_pro;
      }
      return this.i18n.empty_customer_bookings_desc || this.i18n.setup_owner_desc || this.i18n.no_bookings;
    },
    showDateToColumn() {
      return this.bookings.some(b => b.booking_date_to);
    },
    filteredBookings() {
      return this.bookings
          .filter(b => {
            const svc       = (b.service_label  || '').toLowerCase();
            const prov      = (b.provider_name  || '').toLowerCase();
            const fSvc      = this.filter.service.toLowerCase();
            const fProv     = this.filter.provider.toLowerCase();
            const serviceMatch  = svc.includes(fSvc);
            const providerMatch = prov.includes(fProv);
            // Bug 59: for range bookings (booking_date_to set), the filter
            // date should match any day the booking spans, not just the
            // start day. A customer filtering by 2026-06-09 against a
            // booking dated 2026-06-08 -> 2026-06-10 reasonably expects
            // their booking to appear. The old startsWith() returned
            // false and rendered "No bookings match your current
            // filters." for the middle of a range.
            const dateMatch     = this.filter.date
                ? (b.booking_date.startsWith(this.filter.date) ||
                   (b.booking_date_to &&
                    this.filter.date >= b.booking_date.slice(0, 10) &&
                    this.filter.date <= b.booking_date_to.slice(0, 10)))
                : true;
            const statusMatch   = this.filter.status
                ? b.status === this.filter.status
                : true;
            return serviceMatch && providerMatch && dateMatch && statusMatch;
          })
          .sort((a, b) => {
            if (!this.sortKey) return 0;
            const valA = this.normalizeSortValue(a, this.sortKey);
            const valB = this.normalizeSortValue(b, this.sortKey);
            const emptyA = valA === null || valA === undefined || valA === '';
            const emptyB = valB === null || valB === undefined || valB === '';
            if (emptyA && emptyB) return 0;
            if (emptyA) return 1;
            if (emptyB) return -1;
            let cmp = 0;
            if (typeof valA === 'string' && typeof valB === 'string') {
              cmp = valA.localeCompare(valB);
            } else if (valA < valB) {
              cmp = -1;
            } else if (valA > valB) {
              cmp = 1;
            }
            return this.sortAsc ? cmp : -cmp;
          });
    },
    totalPages() {
      return Math.ceil(this.filteredBookings.length / this.pageSize) || 1;
    },
    paginatedBookings() {
      const start = (this.currentPage - 1) * this.pageSize;
      return this.filteredBookings.slice(start, start + this.pageSize);
    }
  },
  watch: {
    // Bug 57: when the user changes the entries-per-page selector or
    // applies/changes a status / service / provider / date filter,
    // currentPage is left at its previous value. With 49 bookings on
    // page 3 of 4 (10/page), switching to 50/page leaves currentPage=3
    // while totalPages drops to 1 -- the UI renders "Page 3 of 1" and
    // paginatedBookings.slice((3-1)*50, ...) returns an empty (or
    // partial) array, so the table looks broken/empty even though
    // there's data to show. Reset to page 1 whenever the underlying
    // page count can change.
    pageSize() {
      this.currentPage = 1;
    },
    'filter.status'() {
      this.currentPage = 1;
    },
    'filter.service'() {
      this.currentPage = 1;
    },
    'filter.provider'() {
      this.currentPage = 1;
    },
    'filter.date'() {
      this.currentPage = 1;
    }
  },
  methods: {
    actionMenuItems(booking) {
      if (!booking) {
        return [];
      }
      const items = [];
      const bookingId = booking.id;
      const loadingState = this.actionLoading[bookingId];

      items.push({
        key: 'view',
        label: this.i18n.view,
        icon: 'view',
        onClick: () => this.viewBooking(booking)
      });

      if (this.canCancel(booking)) {
        items.push({
          key: 'cancel',
          label: this.i18n.cancel,
          icon: 'cancel',
          variant: 'danger',
          disabled: !!loadingState,
          onClick: () => this.cancel(booking)
        });
      }

      if (this.canReschedule(booking)) {
        items.push({
          key: 'reschedule',
          label: this.i18n.reschedule,
          icon: 'reschedule',
          onClick: () => this.openReschedule(booking)
        });
      }

      return items;
    },
    fetchBookings() {
      this.loading = true;
      restRequest('bookaro/v1/bookings/owner')
        .then((res) => {
          const rows = Array.isArray(res) ? res : [];
          this.bookings = rows.map(b => ({
            ...b,
            provider_name:  b.provider_name  || '',
            provider_email: b.provider_email || '',
            provider_phone: b.provider_phone || '',
            cancel_reason:  b.cancel_reason  || ''
          }));
          this.emitNavCounts();
        })
        .catch((err) => this.$emit('open-error', err?.message || this.i18n.fetch_error))
        .finally(() => {
          this.loading = false;
        });
    },
    emitNavCounts() {
      const pendingCount = this.bookings.filter(b => b.status === 'pending').length;
      this.$emit('nav-counts', { bookings: { pending: pendingCount } });
    },
    sortBy(key) {
      if (this.sortKey === key) {
        this.sortAsc = !this.sortAsc;
      } else {
        this.sortKey = key;
        this.sortAsc = true;
      }
    },
    onDateSelect(date) {
      this.filter.date = date;
      this.showDatepicker = false;
      this.currentPage = 1;
    },
    clearFilters() {
      this.filter = { service:'', provider:'', date:'', status:'' };
      this.currentPage = 1;
    },
    cancel(booking) {
      this.cancelBookingTarget = booking;
      this.showCancelModal = true;
    },
    canCancel(booking) {
      const status = booking?.status || '';
      return !['cancelled', 'rejected', 'completed', 'no_show'].includes(status);
    },
    canReschedule(booking) {
      return ['pending', 'approved'].includes(booking.status);
    },
    openReschedule(booking) {
      this.rescheduleBooking = booking;
      this.showRescheduleModal = true;
    },
    closeCancelModal() {
      this.showCancelModal = false;
      this.cancelBookingTarget = null;
    },
    closeRescheduleModal() {
      this.showRescheduleModal = false;
      this.rescheduleBooking = null;
    },
    handleCancelled() {
      this.fetchBookings();
    },
    handleRescheduled() {
      this.fetchBookings();
    },
    viewBooking(booking) {
      this.$emit('open-details', booking);
    },
    rowTouchStart(e) {
      this.touchStartX = e.touches[0].clientX;
      this.touchStartY = e.touches[0].clientY;
    },
    rowTouchEnd(booking, e) {
      const endX = e.changedTouches[0].clientX;
      const endY = e.changedTouches[0].clientY;
      const dx = Math.abs(endX - this.touchStartX);
      const dy = Math.abs(endY - this.touchStartY);
      if (dx < 10 && dy < 10 && window.innerWidth <= 768) {
        this.viewBooking(booking);
      }
    },
    statusLabel(status) {
      return this.i18n[status] || this.i18n.status_unknown || '';
    },
    formatPrice(value) {
      const settings = window.BookaroData?.currency || {};
      const num = Number(value);
      if (Number.isNaN(num)) {
        return '';
      }
      const decimals = Number.isInteger(settings.decimals) ? settings.decimals : 2;
      const decSep = settings.decimal_separator || '.';
      const thouSep = settings.thousand_separator || ',';
      const symbol = settings.symbol || '';
      const format = settings.format || '%1$s%2$s';
      const fixed = num.toFixed(decimals);
      const parts = fixed.split('.');
      const intPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thouSep);
      const number = parts[1] !== undefined ? intPart + decSep + parts[1] : intPart;
      return format.replace('%1$s', symbol).replace('%2$s', number);
    },
    formatDate(dateStr) {
      const format = this.i18n.date_time_format;
      return window.dayjs(dateStr).format(format);
    },
    normalizeSortValue(row, key) {
      if (!row || !key) {
        return '';
      }
      const raw = row[key];
      if (raw === null || raw === undefined) {
        return '';
      }
      if (['booking_date', 'booking_date_to', 'created_at'].includes(key)) {
        const ts = window.dayjs ? window.dayjs(raw).valueOf() : Date.parse(raw);
        return Number.isFinite(ts) ? ts : '';
      }
      if (key === 'price') {
        const num = Number(raw);
        return Number.isFinite(num) ? num : '';
      }
      if (typeof raw === 'string') {
        return raw.toLowerCase();
      }
      return raw;
    }
  },
  mounted() {
    this.fetchBookings();
    this.intervalId = setInterval(this.fetchBookings, 20000);
  },
  beforeUnmount() {
    clearInterval(this.intervalId);
  }
};
</script>
<style scoped>
/* Spinner for full‐screen overlay */
.spinner {
  border: 4px solid rgba(0,0,0,0.1);
  border-top-color: var(--bookaro-dashboard-accent, #3498db);
  border-radius: 50%;
  width: 2rem;
  height: 2rem;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Loader in buttons */
.loader-button {
  border: 2px solid transparent;
  border-top-color: white;
  border-radius: 50%;
  width: 1rem;
  height: 1rem;
  animation: spin 1s linear infinite;
}

.object-cover.border-2.border-gray-200 {
  width: 60px;
  height: 50px;
}

.status-stack {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.status-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.status-label {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--bookaro-dashboard-muted);
  min-width: 6.5rem;
}

</style>
