<template>
  <div class="relative cst-book-min-cont-hei bookaro-bookings-view">
    <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>
    <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.client"
          :placeholder="i18n.owner_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">
        {{ providerEmptyTitle }}
      </h3>
      <p class="mt-1 text-sm text-gray-600">
        {{ providerEmptyDescription }}
      </p>
      <div class="mt-3 flex flex-wrap gap-2">
        <a
          v-if="showCreateListingAction && (createListingUrl || browseUrl)"
          :href="createListingUrl || browseUrl"
          class="bookaro-btn bookaro-btn--primary"
        >
          {{
            createListingUrl
              ? (i18n.empty_action_create_listing || i18n.empty_no_listings_title || i18n.setup_action_browse)
              : (i18n.setup_action_browse || i18n.empty_action_browse_site)
          }}
        </a>
        <button
          v-else-if="showCreateListingAction"
          @click="openSettingsTab"
          class="bookaro-btn bookaro-btn--primary"
        >
          {{ i18n.empty_action_create_listing || i18n.setup_action_settings || i18n.empty_action_open_settings }}
        </button>
        <button
          v-if="showSetAvailabilityAction"
          @click="openSettingsTab"
          class="bookaro-btn"
          :class="showCreateListingAction ? 'bookaro-btn--outline' : 'bookaro-btn--primary'"
        >
          {{ i18n.empty_action_set_availability || i18n.setup_action_settings || i18n.empty_action_open_settings }}
        </button>
        <button
          v-if="showAddServiceAction"
          @click="openServiceAction"
          class="bookaro-btn"
          :class="showSetAvailabilityAction ? 'bookaro-btn--outline' : 'bookaro-btn--primary'"
        >
          {{ i18n.empty_action_add_service || i18n.setup_step_services_title }}
        </button>
        <a
          v-if="showRunTestBookingAction"
          :href="listingUrl"
          class="bookaro-btn"
          :class="(showSetAvailabilityAction || showAddServiceAction) ? 'bookaro-btn--outline' : 'bookaro-btn--primary'"
        >
          {{ i18n.empty_action_run_test_booking || i18n.setup_action_preview || i18n.empty_action_open_listing }}
        </a>
        <a
          v-if="browseUrl && (!hasListings || !listingUrl)"
          :href="browseUrl"
          class="bookaro-btn bookaro-btn--outline"
        >
          {{ i18n.setup_action_browse || i18n.empty_action_browse_site }}
        </a>
      </div>
    </div>

    <div class="bookaro-filter-bar mb-4">
      <div class="bookaro-filter-group">
        <label class="text-sm font-medium text-gray-700">
          {{ i18n.bulk_actions }}
        </label>
        <select v-model="bulkAction" class="bookaro-select">
          <option value="">{{ i18n.bulk_actions }}</option>
          <option v-if="!autoApproveEnabled" value="approved">{{ i18n.approve }}</option>
          <option value="rejected">{{ i18n.reject }}</option>
          <option value="cancelled">{{ i18n.cancel }}</option>
        </select>
        <button
            @click="applyBulkAction"
            :disabled="!canApplyBulk"
            class="bookaro-btn bookaro-btn--primary"
        >
          <span v-if="bulkLoading" class="loader-button mr-1"></span>
          <span v-else>{{ i18n.bulk_apply || i18n.apply }}</span>
        </button>
      </div>
      <button
          @click="selectAllVisible"
          class="bookaro-btn bookaro-btn--outline"
      >
        {{ i18n.bulk_select_all }}
      </button>
      <button
          v-if="selectedCount"
          @click="clearSelection"
          class="bookaro-btn bookaro-btn--ghost"
      >
        {{ i18n.bulk_clear_selection }}
      </button>
      <span v-if="selectedCount" class="text-sm text-gray-600">
        {{ bulkSelectedLabel }}
      </span>
    </div>

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

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

    <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="isWholeDay && 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.owner_name || i18n.owner_name }}
            <span v-if="b.owner_email">({{ b.owner_email }})</span>
          </div>
          <div class="bookaro-booking-card__meta">
            {{ i18n.price_label }}:
            {{ b.price_formatted || formatPrice(b.price) }}
          </div>
        </div>
        <label class="inline-flex items-center gap-2 text-xs text-gray-500">
          <input
            type="checkbox"
            :checked="isSelected(b.id)"
            @change="toggleSelect(b.id, $event)"
            :aria-label="i18n.select_booking"
          />
          {{ i18n.select_booking }}
        </label>
        <div class="bookaro-booking-card__actions">
          <button
            v-if="b.status === 'pending' && !autoApproveEnabled"
            @click="updateStatus(b.id, 'approved')"
            :disabled="actionLoading[b.id] === 'approved'"
            class="bookaro-btn bookaro-btn--action-approve bookaro-btn--sm"
          >
            <ActionIcon name="approve" />
            <span>{{ i18n.approve }}</span>
          </button>
          <button
            v-if="b.status === 'pending'"
            @click="updateStatus(b.id, 'rejected')"
            :disabled="actionLoading[b.id] === 'rejected'"
            class="bookaro-btn bookaro-btn--action-reject bookaro-btn--sm"
          >
            <ActionIcon name="reject" />
            <span>{{ i18n.reject }}</span>
          </button>
          <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="b.status === 'approved'"
            @click="addNote(b)"
            :disabled="actionLoading[b.id]"
            class="bookaro-btn bookaro-btn--action-note bookaro-btn--sm"
          >
            <ActionIcon name="note" />
            <span>{{ i18n.add_note }}</span>
          </button>
          <button
            v-if="b.status === 'approved'"
            @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
            @click="openReschedule(b)"
            :disabled="!canReschedule(b)"
            class="bookaro-btn bookaro-btn--action-reschedule bookaro-btn--sm"
            :class="canReschedule(b) ? '' : 'opacity-60 cursor-not-allowed'"
          >
            <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>

    <div class="bookaro-table-wrapper overflow-x-auto">
      <table class="bookaro-table">
        <thead>
        <tr>
          <th class="text-left w-8">
            <input
                type="checkbox"
                :checked="allVisibleSelected"
                @change="toggleSelectAll($event)"
                :aria-label="i18n.select_all"
            />
          </th>
          <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('owner_name')" class="text-left cursor-pointer whitespace-nowrap min-w-[200px]">
            {{ i18n.owner_name }}
            <span v-if="sortKey === 'owner_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="isWholeDay" @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('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>
            <input
                type="checkbox"
                :checked="isSelected(b.id)"
                @change="toggleSelect(b.id, $event)"
                :aria-label="i18n.select_booking"
            />
          </td>
          <td>
            {{ b.service_label || i18n.placeholder_dash }}
          </td>
          <td class="min-w-[200px] break-words">
            {{ b.owner_name }}<br/>
            <small><strong>{{ i18n.email }}: {{ b.owner_email }}</strong></small><br/>
            <small><strong>{{ i18n.phone }}: {{ b.customer_phone }}</strong></small>
          </td>
          <td>{{ formatDate(b.created_at) }}</td>
          <td>{{ formatDate(b.booking_date) }}</td>
          <td v-if="isWholeDay">{{ b.booking_date_to ? formatDate(b.booking_date_to) : i18n.placeholder_dash }}</td>
          <td>{{ b.price_formatted || formatPrice(b.price) }}</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
                  v-if="b.status === 'pending' && !autoApproveEnabled"
                  @click="updateStatus(b.id, 'approved')"
                  :disabled="actionLoading[b.id] === 'approved'"
                  class="bookaro-btn bookaro-btn--action-approve bookaro-btn--sm"
              >
                <svg
                    v-if="actionLoading[b.id] === 'approved'"
                    class="animate-spin h-4 w-4 mr-1 text-white"
                    viewBox="0 0 24 24"
                >
                  <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
                  <path
                      class="opacity-75"
                      fill="currentColor"
                      d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
                  />
                </svg>
                <template v-else>
                  <ActionIcon name="approve" />
                  <span>{{ i18n.approve }}</span>
                </template>
              </button>
              <button
                  v-if="b.status === 'pending'"
                  @click="updateStatus(b.id, 'rejected')"
                  :disabled="actionLoading[b.id] === 'rejected'"
                  class="bookaro-btn bookaro-btn--action-reject bookaro-btn--sm"
              >
                <svg
                    v-if="actionLoading[b.id] === 'rejected'"
                    class="animate-spin h-4 w-4 mr-1 text-white"
                    viewBox="0 0 24 24"
                >
                  <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
                  <path
                      class="opacity-75"
                      fill="currentColor"
                      d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
                  />
                </svg>
                <template v-else>
                  <ActionIcon name="reject" />
                  <span>{{ i18n.reject }}</span>
                </template>
              </button>
              <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="b.status === 'approved'"
                  @click="addNote(b)"
                  :disabled="actionLoading[b.id]"
                  class="bookaro-btn bookaro-btn--action-note bookaro-btn--sm"
              >
                <template v-if="actionLoading[b.id]">
                  <span class="loader-button mr-1"></span>
                </template>
                <template v-else>
                  <ActionIcon name="note" />
                  <span>{{ i18n.add_note }}</span>
                </template>
              </button>
              <button
                  v-if="b.status === 'approved'"
                  @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
                  @click="openReschedule(b)"
                  :disabled="!canReschedule(b)"
                  class="bookaro-btn bookaro-btn--action-reschedule bookaro-btn--sm"
                  :class="canReschedule(b) ? '' : 'opacity-60 cursor-not-allowed'"
              >
                <ActionIcon name="reschedule" />
                <span>{{ i18n.reschedule }}</span>
              </button>
              </template>
            </div>
          </td>
        </tr>
        <tr v-if="showFilteredEmptyState">
          <td :colspan="isWholeDay ? 9 : 8" class="text-center py-4 text-gray-500">
            {{ i18n.empty_filtered_results || i18n.no_bookings }}
          </td>
        </tr>
        </tbody>
      </table>
    </div>

    <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 DatePicker from '@bookaro-free/components/DatePicker.vue';
import CancelBookingModal from '@bookaro-free/components/modals/CancelBookingModal.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: 'BookingsView',
  components: { DatePicker, CancelBookingModal, RescheduleModal, ActionIcon, ActionsMenu },
  props: {
    i18n: { type: Object, required: true }
  },
  data() {
    return {
      bookings: [],
      loading: true,
      filter: { service: '', client: '', date: '', status: '' },
      showDatepicker: false,
      sortKey: 'created_at',
      sortAsc: false,
      pageSizes: [5, 10, 25, 50],
      pageSize: 10,
      currentPage: 1,
      actionLoading: {},
      touchStartX: 0,
      touchStartY: 0,
      isWholeDay: !!window.BookaroData?.is_whole_day,
      showCancelModal: false,
      cancelBookingTarget: null,
      showRescheduleModal: false,
      rescheduleBooking: null,
      selectedIds: [],
      bulkAction: '',
      bulkLoading: false
    };
  },
  computed: {
    autoApproveEnabled() {
      return !!window.BookaroData?.auto_approve_bookings;
    },
    isCompact() {
      return (window.BookaroData?.dashboard_density || '') === 'compact';
    },
    setupData() {
      return window.BookaroData?.setup || null;
    },
    listingUrl() {
      return this.setupData?.listing_url || '';
    },
    createListingUrl() {
      return this.setupData?.create_listing_url || '';
    },
    editListingUrl() {
      return this.setupData?.edit_listing_url || '';
    },
    browseUrl() {
      return this.setupData?.browse_url || '';
    },
    hasTimeslots() {
      return !!this.setupData?.has_timeslots;
    },
    hasServices() {
      return !!this.setupData?.has_services;
    },
    hasListings() {
      if (!this.setupData || typeof this.setupData.has_listings === 'undefined') {
        return true;
      }
      return !!this.setupData.has_listings;
    },
    isPro() {
      return !!window.BookaroData?.is_pro;
    },
    canManageServices() {
      return !!window.BookaroData?.provider_services_allowed;
    },
    hasActiveFilters() {
      return !!(
        this.filter.service ||
        this.filter.client ||
        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;
    },
    providerEmptyTitle() {
      return this.i18n.empty_provider_bookings_title || this.i18n.setup_step_test_title || this.i18n.no_bookings;
    },
    providerEmptyDescription() {
      if (!this.hasListings && this.i18n.empty_provider_bookings_desc_missing_listings) {
        return this.i18n.empty_provider_bookings_desc_missing_listings;
      }
      if (!this.hasTimeslots && this.i18n.empty_provider_bookings_desc_missing_timeslots) {
        return this.i18n.empty_provider_bookings_desc_missing_timeslots;
      }
      if (!this.hasServices && this.i18n.empty_provider_bookings_desc_missing_services) {
        return this.i18n.empty_provider_bookings_desc_missing_services;
      }
      if (this.isPro && this.i18n.empty_provider_bookings_desc_pro) {
        return this.i18n.empty_provider_bookings_desc_pro;
      }
      return this.i18n.empty_provider_bookings_desc || this.i18n.setup_step_test_desc || this.i18n.no_bookings;
    },
    showCreateListingAction() {
      return !this.hasListings;
    },
    showSetAvailabilityAction() {
      return this.hasListings && !this.hasTimeslots;
    },
    showAddServiceAction() {
      return this.hasListings && !this.hasServices && (this.canManageServices || !!this.editListingUrl);
    },
    showRunTestBookingAction() {
      return this.hasListings && this.hasServices && this.hasTimeslots && !!this.listingUrl;
    },
    filteredBookings() {
      return this.bookings
          .filter(b => {
            // Defensive: missing/null service_label or owner_name (could
            // happen for a deleted-service booking or a GDPR-anonymized
            // customer, see Bug 38/42 area) would crash the whole list
            // with "Cannot read properties of undefined (reading
            // toLowerCase)" — mirror the OwnerBookingsView guards.
            const svc       = (b.service_label || '').toLowerCase();
            const client    = (b.owner_name    || '').toLowerCase();
            const serviceMatch = svc.includes(this.filter.service.toLowerCase());
            const clientMatch = client.includes(this.filter.client.toLowerCase());
            // Bug 59: sibling fix to OwnerBookingsView — match the filter
            // date against any day a range booking spans, not just the
            // start day.
            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 && clientMatch && 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);
    },
    selectedBookings() {
      if (!this.selectedIds.length) {
        return [];
      }
      const selectedSet = new Set(this.selectedIds);
      return this.bookings.filter(b => selectedSet.has(b.id));
    },
    selectedCount() {
      return this.selectedIds.length;
    },
    bulkSelectedLabel() {
      const label = this.i18n.bulk_selected_count;
      return `${label} ${this.selectedCount}`;
    },
    allVisibleSelected() {
      if (!this.paginatedBookings.length) {
        return false;
      }
      const selectedSet = new Set(this.selectedIds);
      return this.paginatedBookings.every(b => selectedSet.has(b.id));
    },
    eligibleBulkIds() {
      if (!this.bulkAction) {
        return [];
      }
      return this.selectedBookings
        .filter(b => this.isBulkEligible(b, this.bulkAction))
        .map(b => b.id);
    },
    canApplyBulk() {
      return !!(this.bulkAction && this.selectedCount && !this.bulkLoading);
    }
  },
  watch: {
    // Bug 57: reset currentPage to 1 whenever the filter/pageSize changes
    // so the UI never lands on a page that no longer exists (e.g.
    // "Page 3 of 1" with an empty body). Sibling fix to OwnerBookingsView.
    pageSize() {
      this.currentPage = 1;
    },
    'filter.status'() {
      this.currentPage = 1;
    },
    'filter.service'() {
      this.currentPage = 1;
    },
    'filter.client'() {
      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];

      if (booking.status === 'pending' && !this.autoApproveEnabled) {
        items.push({
          key: 'approve',
          label: this.i18n.approve,
          icon: 'approve',
          disabled: loadingState === 'approved',
          onClick: () => this.updateStatus(bookingId, 'approved')
        });
      }
      if (booking.status === 'pending') {
        items.push({
          key: 'reject',
          label: this.i18n.reject,
          icon: 'reject',
          variant: 'danger',
          disabled: loadingState === 'rejected',
          onClick: () => this.updateStatus(bookingId, 'rejected')
        });
      }
      items.push({
        key: 'view',
        label: this.i18n.view,
        icon: 'view',
        onClick: () => this.viewBooking(booking)
      });
      if (booking.status === 'approved') {
        items.push({
          key: 'note',
          label: this.i18n.add_note,
          icon: 'note',
          disabled: !!loadingState,
          onClick: () => this.addNote(booking)
        });
        items.push({
          key: 'cancel',
          label: this.i18n.cancel,
          icon: 'cancel',
          variant: 'danger',
          disabled: !!loadingState,
          onClick: () => this.cancel(booking)
        });
      }
      items.push({
        key: 'reschedule',
        label: this.i18n.reschedule,
        icon: 'reschedule',
        disabled: !this.canReschedule(booking),
        onClick: () => this.openReschedule(booking)
      });

      return items;
    },
    fetchBookings() {
      this.loading = true;
      restRequest('bookaro/v1/bookings/provider')
        .then((res) => {
          const rows = Array.isArray(res) ? res : [];
          this.bookings = rows.map(b => ({
            ...b,
            cancel_reason: b.cancel_reason || ''
          }));
          const existingIds = new Set(this.bookings.map(b => b.id));
          this.selectedIds = this.selectedIds.filter(id => existingIds.has(id));
          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: '', client: '', date: '', status: '' };
      this.currentPage = 1;
    },
    openSettingsTab() {
      window.location.hash = '#settings';
    },
    openServiceAction() {
      if (this.canManageServices) {
        window.location.hash = '#services';
        return;
      }
      if (this.editListingUrl) {
        window.location.href = this.editListingUrl;
        return;
      }
      this.openSettingsTab();
    },
    isSelected(id) {
      return this.selectedIds.includes(id);
    },
    toggleSelect(id, event) {
      const checked = event?.target?.checked;
      if (checked) {
        if (!this.selectedIds.includes(id)) {
          this.selectedIds = [...this.selectedIds, id];
        }
      } else {
        this.selectedIds = this.selectedIds.filter(selectedId => selectedId !== id);
      }
    },
    toggleSelectAll(event) {
      const checked = event?.target?.checked;
      if (checked) {
        this.selectAllVisible();
        return;
      }
      const visibleIds = this.paginatedBookings.map(b => b.id);
      this.selectedIds = this.selectedIds.filter(id => !visibleIds.includes(id));
    },
    selectAllVisible() {
      const visibleIds = this.paginatedBookings.map(b => b.id);
      if (!visibleIds.length) {
        return;
      }
      const set = new Set(this.selectedIds);
      visibleIds.forEach(id => set.add(id));
      this.selectedIds = Array.from(set);
    },
    clearSelection() {
      this.selectedIds = [];
    },
    isBulkEligible(booking, action) {
      const status = booking.status;
      if (action === 'approved') {
        if (this.autoApproveEnabled) {
          return false;
        }
        return status === 'pending';
      }
      if (action === 'rejected') {
        return status === 'pending';
      }
      if (action === 'cancelled') {
        return !['cancelled', 'rejected', 'completed', 'no_show'].includes(status);
      }
      return false;
    },
    applyBulkAction() {
      if (!this.selectedCount) {
        this.$emit('open-error', this.i18n.bulk_no_selection || this.i18n.generic_error);
        return;
      }
      if (!this.bulkAction) {
        return;
      }
      const ids = this.eligibleBulkIds;
      if (!ids.length) {
        this.$emit('open-error', this.i18n.bulk_no_eligible || this.i18n.generic_error);
        return;
      }
      this.bulkLoading = true;
      restRequest('bookaro/v1/bookings/bulk-status', {
        method: 'POST',
        data: {
          bulk_action: this.bulkAction,
          booking_ids: ids
        }
      })
        .then((res) => {
          if (res?.failed?.length) {
            this.$emit('open-error', this.i18n.bulk_partial || this.i18n.update_error);
          }
          this.fetchBookings();
          this.selectedIds = [];
          this.bulkAction = '';
        })
        .catch((err) => this.$emit('open-error', err?.message || this.i18n.update_error))
        .finally(() => {
          this.bulkLoading = false;
        });
    },
    updateStatus(id, status) {
      this.actionLoading[id] = status;
      restRequest(`bookaro/v1/bookings/${id}/status`, {
        method: 'POST',
        data: { status }
      })
        .then(() => {
          this.fetchBookings();
        })
        .catch((err) => this.$emit('open-error', err?.message || this.i18n.update_error))
        .finally(() => { delete this.actionLoading[id]; });
    },
    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 target = e.target;
      if (target && typeof target.closest === 'function') {
        const interactive = target.closest('button, input, a, select, textarea');
        if (interactive) {
          return;
        }
      }
      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);
      }
    },
    addNote(booking) {
      this.$emit('open-note', booking, this.i18n.add_note_title);
    },
    cancel(booking) {
      this.cancelBookingTarget = booking;
      this.showCancelModal = true;
    },
    canReschedule(booking) {
      const status = (booking?.status || '').toString().toLowerCase();
      if (!status) {
        return false;
      }
      if (['cancelled', 'rejected', 'no_show', 'completed'].includes(status)) {
        return false;
      }
      return true;
    },
    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();
    },
    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>
.loader-button {
  border: 2px solid transparent;
  border-top-color: white;
  border-radius: 50%;
  width: 1rem;
  height: 1rem;
  animation: spin 1s linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
.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>
