<!-- File: assets/js/ProviderDashboard.vue -->
<template>
  <div
    id="bookaro-provider-dashboard"
    class="vue-wrapper flex bookaro-scope bookaro-provider-dashboard bookaro-dashboard-shell"
    :class="{ 'bookaro-dashboard--compact': isCompact }"
  >
    <!-- ─── Main Content ─── -->
    <main class="flex-1 relative overflow-x-auto bookaro-dashboard-main">
      <header class="bookaro-dashboard-header md:hidden">
        <h2 class="text-xl font-semibold text-gray-900">
          {{ currentViewTitle }}
        </h2>
      </header>

      <DashboardNav
        :items="navItems"
        :active-key="currentView"
        @select="switchTo"
      />

      <div v-if="showSetupToggle" class="bookaro-setup-toggle">
        <button
          type="button"
          class="bookaro-setup-toggle__button"
          @click="restoreSetup"
        >
          {{ i18n.setup_show_checklist || i18n.setup_checklist_title }}
        </button>
      </div>

      <section v-if="showSetupCards" class="bookaro-dashboard-page">
        <div class="bookaro-card bookaro-card__body bookaro-setup-panel">
          <div class="bookaro-setup-panel__header">
            <div>
              <h3 class="text-lg font-semibold text-gray-900">
                {{ i18n.setup_checklist_title }}
              </h3>
              <p class="text-sm text-gray-600">
                {{ i18n.setup_checklist_desc }}
              </p>
            </div>
            <div class="bookaro-setup-panel__actions">
              <div class="bookaro-setup-progress">
                <span class="bookaro-setup-progress__label">
                  {{ setupCompletedCount }}/{{ setupCards.length }} {{ i18n.setup_progress_label }}
                </span>
                <div class="bookaro-setup-progress__bar">
                  <span
                    class="bookaro-setup-progress__fill"
                    :style="{ width: setupProgressPercent + '%' }"
                  ></span>
                </div>
              </div>
              <button
                type="button"
                class="bookaro-btn bookaro-btn--ghost text-xs"
                @click="dismissSetup"
              >
                {{ i18n.dismiss }}
              </button>
            </div>
          </div>

          <div class="bookaro-setup-steps">
            <div
              v-for="(card, index) in setupCards"
              :key="card.id"
              :class="[
                'bookaro-setup-step',
                card.complete ? 'is-complete' : ''
              ]"
            >
              <div class="bookaro-setup-step__header">
                <div
                  :class="[
                    'bookaro-setup-step__badge',
                    card.complete ? 'is-complete' : ''
                  ]"
                >
                  <span v-if="card.complete" aria-hidden="true">&#10003;</span>
                  <span v-else>{{ index + 1 }}</span>
                </div>
                <div class="flex-1">
                  <p class="text-sm font-semibold text-gray-900 bookaro-setup-step__title">{{ card.title }}</p>
                  <p class="text-xs text-gray-600 bookaro-setup-step__desc">{{ card.description }}</p>
                </div>
              </div>
              <div v-if="!card.complete" class="bookaro-setup-step__action">
                <button
                  v-if="card.tab"
                  type="button"
                  class="bookaro-btn bookaro-btn--primary text-xs"
                  @click="handleSetupAction(card)"
                >
                  {{ card.actionLabel }}
                </button>
                <a
                  v-else-if="card.url"
                  class="bookaro-btn bookaro-btn--primary text-xs"
                  :href="card.url"
                >
                  {{ card.actionLabel }}
                </a>
              </div>
            </div>
          </div>
        </div>
      </section>

      <!-- Modals (Error, Note, Details) -->
      <ErrorModal
          :show="showErrorModal"
          :message="errorMessage"
          @close="showErrorModal = false"
      />
      <NoteModal
          :show="showNoteModal"
          :booking="noteBooking"
          :title="modalTitle"
          :saving="modalSaving"
          :prefill-text="
          modalType === 'cancelled'
            ? ''
            : (noteBooking ? noteBooking.notes : '')
        "
          @close="showNoteModal = false"
          @save="onModalSave"
          :i18n="i18n"
      />
      <DetailsModal
          :show="showDetailsModal"
          :booking="detailsBooking"
          :loading="detailsLoading"
          @close="showDetailsModal = false"
          :i18n="i18n"
      />

      <!-- Dynamically mount either BookingsView or SettingsLayout -->
      <div v-if="currentView === 'bookings'" class="bookaro-dashboard-page">
        <!-- BookingsView.vue manages its own props/events -->
        <BookingsView
            :i18n="i18n"
            :loading="bookingsLoading"
            @open-error="showError"
            @open-note="handleOpenNote"
            @open-details="viewBooking"
            @nav-counts="handleNavCounts"
        />
      </div>

      <div v-else-if="currentView === 'calendar'" class="bookaro-dashboard-page">
        <CalendarView
            :i18n="i18n"
            @open-error="showError"
            @open-note="handleOpenNote"
            @open-details="viewBooking"
        />
      </div>

      <div v-else-if="currentView === 'services'" class="bookaro-dashboard-page">
        <ServicesView
            :i18n="i18n"
            @open-error="showError"
        />
      </div>

      <div v-else-if="currentView === 'settings'" class="bookaro-dashboard-page">
        <!-- Explicitly pass v-model bindings down into SettingsLayout -->
        <SettingsLayout
            :i18n="i18n"
            :loading="settingsLoading"
            v-model:availability="availability"
            :schedule-meta="scheduleMeta"
            v-model:exceptionDates="exceptionDates"
            v-model:exceptionMonth="exceptionMonth"
            :exception-month-days="exceptionMonthDays"
            :saving-settings="savingSettings"
            :settings-message="settingsMessage"
            :exception-conflicts="exceptionConflicts"
            @save-settings="saveSettings"
        />
      </div>

    </main>
  </div>
</template>

<script>
import $ from 'jquery';
import { restRequest } from '@bookaro-free/js/rest';
import ProviderBookingsView from './pages/ProviderBookingsView.vue';
import ProviderCalendarView from './pages/ProviderCalendarView.vue';
import ProviderServicesView from './pages/ProviderServicesView.vue';
import ProviderSettingsView from '@bookaro-provider-settings';
import DashboardNav from './components/dashboard/DashboardNav.vue';
import NoteModal from '@bookaro-free/components/modals/NoteModal.vue';
import DetailsModal from '@bookaro-free/components/modals/DetailsModal.vue';
import ErrorModal from '@bookaro-free/components/modals/ErrorModal.vue';

export default {
  name: 'ProviderDashboard',
  components: {
    BookingsView: ProviderBookingsView,
    CalendarView: ProviderCalendarView,
    ServicesView: ProviderServicesView,
    SettingsLayout: ProviderSettingsView,
    DashboardNav,
    NoteModal,
    DetailsModal,
    ErrorModal
  },
  data() {
    return {
      // Active tab: “bookings” or “settings”
      currentView: 'bookings',
      navCounts: {
        bookings: { pending: 0 }
      },

      // ─── BOOKINGS STATE ───
      bookingsLoading: false,
      // (BookingsView.vue fetches its own data inside its mounted)

      // ─── MODAL STATE ───
      showErrorModal: false,
      errorMessage: '',
      showNoteModal: false,
      noteBooking: null,
      modalTitle: '',
      modalType: '', // 'note' or 'cancelled'
      modalSaving: false,
      showDetailsModal: false,
      detailsBooking: null,
      detailsLoading: false,
      setupDismissed: false,

      // ─── SETTINGS STATE ───
      settingsLoading: false,
      exceptionMonth: window.dayjs().startOf('month'),
      exceptionDates: [],
      scheduleMeta: {
        using_default_template: false,
        has_saved_schedule: false,
        buffer_before_minutes: 0,
        buffer_after_minutes: 0,
        buffer_summary: '',
        guidance: {
          title: '',
          description: '',
          items: []
        }
      },

      availability: {
        weekdays: [],
        interval: 30,
        slots: 1,
        times: {
          Sun: [],
          Mon: [],
          Tue: [],
          Wed: [],
          Thu: [],
          Fri: [],
          Sat: []
        }
      },
      savingSettings: false,
      settingsMessage: '',
      // Bug 61: list of pending/approved bookings that fall on dates
      // the provider just closed; populated from the AJAX response so
      // the Exceptions tab can show a warning banner.
      exceptionConflicts: []
    };
  },
  computed: {
    i18n() {
      return window.BookaroData?.i18n || {};
    },
    isCompact() {
      return (window.BookaroData?.dashboard_density || '') === 'compact';
    },
    setupData() {
      return window.BookaroData?.setup || null;
    },
    setupCards() {
      const setupNoticeEnabled = window.BookaroData?.setup_notice_enabled;
      if (setupNoticeEnabled === false) {
        return [];
      }
      const injectedSteps = window.BookaroData?.setup_steps;
      if (Array.isArray(injectedSteps)) {
        return injectedSteps.map(step => this.normalizeSetupStep(step));
      }
      const setup = this.setupData;
      if (!setup) {
        return [];
      }
      const listingUrl = setup.listing_url || '';
      const editListingUrl = setup.edit_listing_url || listingUrl;
      const createListingUrl = setup.create_listing_url || '';
      const hasListings = typeof setup.has_listings === 'undefined' ? true : !!setup.has_listings;
      const setupBrowseUrl = setup.browse_url || '';
      const flags = window.BookaroData?.setup_notice_flags || {};

      const cards = [];
      if (!hasListings && flags.services !== false) {
        cards.push({
          id: 'listing',
          title: this.i18n.empty_action_create_listing || this.i18n.empty_no_listings_title || this.i18n.setup_step_services_title,
          description: this.i18n.empty_provider_bookings_desc_missing_listings || this.i18n.empty_no_listings_desc || this.i18n.no_listings,
          complete: false,
          actionLabel: this.i18n.empty_action_create_listing || this.i18n.setup_action_browse,
          url: createListingUrl || setupBrowseUrl
        });
      }
      if (flags.timeslots !== false) {
        cards.push({
          id: 'timeslots',
          title: this.i18n.setup_step_timeslots_title,
          description: this.i18n.setup_step_timeslots_desc,
          complete: !!setup.has_timeslots,
          actionLabel: this.i18n.setup_action_settings || this.i18n.settings_tab,
          tab: 'settings',
          settingsTab: 'availability'
        });
      }
      if (this.canManageServices && flags.services !== false && hasListings) {
        cards.push({
          id: 'services',
          title: this.i18n.setup_step_services_title,
          description: this.i18n.setup_step_services_desc || this.i18n.no_services_msg,
          complete: !!setup.has_services,
          actionLabel: editListingUrl ? this.i18n.edit_listing : '',
          url: editListingUrl || ''
        });
      }
      if (listingUrl && hasListings) {
        cards.push({
          id: 'test_booking',
          title: this.i18n.setup_step_test_title,
          description: this.i18n.setup_step_test_desc,
          complete: !!setup.has_bookings,
          actionLabel: this.i18n.setup_action_preview || this.i18n.book_now,
          url: listingUrl
        });
      }
      return cards.map(card => this.normalizeSetupStep(card));
    },
    setupCompletedCount() {
      return this.setupCards.filter(card => card.complete).length;
    },
    setupProgressPercent() {
      if (!this.setupCards.length) {
        return 0;
      }
      return Math.round((this.setupCompletedCount / this.setupCards.length) * 100);
    },
    setupHasIncomplete() {
      return this.setupCards.some(card => !card.complete);
    },
    showSetupCards() {
      return this.setupHasIncomplete && !this.setupDismissed;
    },
    showSetupToggle() {
      return this.setupHasIncomplete && this.setupDismissed;
    },
    isGenericMode() {
      return (window.BookaroData?.integration_mode || '') === 'generic';
    },
    providerServicesAllowed() {
      return !!window.BookaroData?.provider_services_allowed;
    },
    canManageServices() {
      return this.isGenericMode && this.providerServicesAllowed;
    },
    navItems() {
      return [
        {
          key: 'bookings',
          label: this.i18n.bookings_tab,
          icon: 'bookings',
          count: this.navCounts?.bookings?.pending || 0,
          countLabel: this.i18n.pending
        },
        {
          key: 'calendar',
          label: this.i18n.calendar_tab,
          icon: 'calendar'
        },
        {
          key: 'services',
          label: this.i18n.services_tab,
          icon: 'services',
          hidden: !this.canManageServices
        },
        {
          key: 'settings',
          label: this.i18n.settings_tab,
          icon: 'settings'
        }
      ];
    },
    currentViewTitle() {
      if (this.currentView === 'bookings') {
        return this.i18n.bookings_tab;
      }
      if (this.currentView === 'calendar') {
        return this.i18n.calendar_tab;
      }
      if (this.currentView === 'services') {
        return this.i18n.services_tab;
      }
      return this.i18n.settings_tab;
    },
    // For the ExceptionsTab calendar:
    exceptionMonthDays() {
      const start = this.exceptionMonth.startOf('month').startOf('week');
      const end = this.exceptionMonth.endOf('month').endOf('week');
      const days = [];
      let d = start.clone();
      while (d.isBefore(end) || d.isSame(end, 'day')) {
        days.push(d.clone());
        d = d.add(1, 'day');
      }
      return days;
    }
  },
  methods: {
    switchTo(tab) {
      if (tab === 'services' && !this.canManageServices) {
        tab = 'bookings';
      }
      this.currentView = tab;

      window.location.hash = `#${tab}`;

      if (tab === 'settings') {
        // Fetch settings as soon as “Settings” is clicked
        this.fetchSettings();
      }
      // (Bookings tab fetch is handled in BookingsView.vue itself)
    },

    updateFromHash() {
      const hash = window.location.hash.replace('#', '');
      const tabs = this.canManageServices
        ? ['bookings', 'calendar', 'services', 'settings']
        : ['bookings', 'calendar', 'settings'];
      if (!tabs.includes(hash)) {
        return;
      }
      this.currentView = hash;
      if (hash === 'settings') {
        this.fetchSettings();
      }
    },
    setupStorageKey() {
      const userId = window.BookaroData?.user_id || 0;
      return `bookaro_setup_provider_dismissed_${userId}`;
    },
    loadSetupDismissed() {
      const key = this.setupStorageKey();
      if (!key) {
        return;
      }
      try {
        this.setupDismissed = window.localStorage && window.localStorage.getItem(key) === '1';
      } catch (e) {
        this.setupDismissed = false;
      }
    },
    dismissSetup() {
      const key = this.setupStorageKey();
      this.setupDismissed = true;
      if (!key) {
        return;
      }
      try {
        window.localStorage.setItem(key, '1');
      } catch (e) {
        // Ignore storage errors.
      }
    },
    normalizeSetupStep(step) {
      if (!step || typeof step !== 'object') {
        return step;
      }
      const normalized = { ...step };
      if (!normalized.tab && typeof normalized.url === 'string') {
        const mapped = this.resolveSetupTabFromUrl(normalized.url);
        if (mapped) {
          normalized.tab = mapped.tab;
          if (mapped.settingsTab) {
            normalized.settingsTab = mapped.settingsTab;
          }
        }
      }
      if (normalized.tab === 'settings' && !normalized.settingsTab) {
        normalized.settingsTab = 'availability';
      }
      return normalized;
    },
    resolveSetupTabFromUrl(url) {
      if (!url || typeof url !== 'string') {
        return null;
      }
      try {
        const parsed = new URL(url, window.location.origin);
        const tab = parsed.searchParams.get('tab');
        if (!tab) {
          return null;
        }
        return { tab: 'settings', settingsTab: tab };
      } catch (e) {
        return null;
      }
    },
    handleSetupAction(card) {
      if (!card || typeof card !== 'object') {
        return;
      }
      if (card.tab) {
        if (card.tab === 'settings' && card.settingsTab) {
          this.setSettingsTabParam(card.settingsTab);
        }
        this.switchTo(card.tab);
        return;
      }
      if (card.url) {
        window.location.href = card.url;
      }
    },
    setSettingsTabParam(tab) {
      try {
        const url = new URL(window.location.href);
        url.searchParams.set('tab', tab);
        window.history.replaceState(null, '', url.pathname + url.search);
      } catch (e) {
        // Ignore URL update errors.
      }
    },
    restoreSetup() {
      const key = this.setupStorageKey();
      this.setupDismissed = false;
      if (!key) {
        return;
      }
      try {
        window.localStorage.removeItem(key);
      } catch (e) {
        // Ignore storage errors.
      }
    },

    // ─── MODAL HANDLERS ───
    showError(msg) {
      this.errorMessage = msg;
      this.showErrorModal = true;
    },
    handleOpenNote(booking, title, type = 'note') {
      this.noteBooking = booking;
      this.modalTitle = title;
      this.modalType = type; // 'note' vs. 'cancelled'
      this.showNoteModal = true;
    },
    handleNavCounts(payload) {
      if (!payload || typeof payload !== 'object') {
        return;
      }
      const next = { ...this.navCounts };
      if (payload.bookings) {
        next.bookings = { ...(next.bookings || {}), ...(payload.bookings || {}) };
      }
      this.navCounts = next;
    },
    viewBooking(booking) {
      this.detailsBooking = booking;
      this.showDetailsModal = true;
    },
    onModalSave(text) {
      if (!this.noteBooking) return;
      this.modalSaving = true;

      const isCancel = this.modalType === 'cancelled';
      const bookingId = this.noteBooking.id;
      const request = isCancel
        ? restRequest(`bookaro/v1/bookings/${bookingId}/cancel`, {
            method: 'POST',
            data: { cancel_reason: text }
          })
        : restRequest(`bookaro/v1/bookings/${bookingId}/note`, {
            method: 'POST',
            data: { note: text }
          });

      request
        .catch((err) => {
          this.showError(err?.message || this.i18n.generic_error);
        })
        .finally(() => {
          this.modalSaving = false;
          this.showNoteModal = false;
        });
    },

    // ─── SETTINGS: fetch & save ───
    fetchSettings() {
      this.settingsLoading = true;

      $.post(window.BookaroData.ajax_url, {
        action: 'bookaro_get_settings',
        security: window.BookaroData.ajax_nonce
      })
          .done(res => {
            if (!res.success) {
              this.showError(res.data || this.i18n.fetch_error);
              return;
            }

            // Populate “availability”
            this.availability = this.normalizeAvailability(res.data.availability || {});
            this.scheduleMeta = this.normalizeScheduleMeta(res.data.schedule_meta || {});
            // Normalize timeslots HH:MM:SS → HH:MM

            // Populate “exceptions” (flag===0 means closed)
            const raw = res.data.exceptions || {};
            this.exceptionDates = Object.entries(raw)
                .filter(([_, flag]) => Number(flag) === 0)
                .map(([date]) => date)
                .sort();
          })
          .fail(() => {
            this.showError(this.i18n.fetch_error);
          })
          .always(() => {
            this.settingsLoading = false;
          });
    },
    saveSettings() {
      this.savingSettings = true;
      this.settingsMessage = '';
      // Bug 61: clear the previous run's conflicts so a clean save
      // removes the banner instead of leaving stale data on screen.
      this.exceptionConflicts = [];

      const payload = {
        availability: JSON.stringify(this.availability),
        exceptions: JSON.stringify(this.exceptionDates)
      };

      $.post(window.BookaroData.ajax_url, {
        action: 'bookaro_save_settings',
        security: window.BookaroData.ajax_nonce,
        ...payload
      })
          .done(res => {
            this.settingsMessage = res.success
                ? this.i18n.settings_saved
                : (res.data || this.i18n.settings_error);

            if (res.success) {
              // Bug 61: surface conflicting bookings the server detected
              // on dates the provider just closed. The save still went
              // through (provider may have intentionally closed despite
              // the bookings), but the banner gives them the IDs to go
              // cancel/reschedule manually.
              const data = res.data || {};
              this.exceptionConflicts = Array.isArray(data.exception_conflicts)
                  ? data.exception_conflicts
                  : [];
              // Re‐fetch everything so the UI shows the new values immediately
              this.fetchSettings();
            }
          })
          .fail(() => {
            this.showError(this.i18n.settings_error);
          })
          .always(() => {
            this.savingSettings = false;
          });
    },
    emptyAvailability() {
      return {
        weekdays: [],
        interval: 30,
        slots: 1,
        times: {
          Sun: [],
          Mon: [],
          Tue: [],
          Wed: [],
          Thu: [],
          Fri: [],
          Sat: []
        }
      };
    },
    normalizeAvailability(payload) {
      const normalized = this.emptyAvailability();
      const source = payload && typeof payload === 'object' ? payload : {};

      normalized.weekdays = Array.isArray(source.weekdays)
        ? source.weekdays.filter(day => Object.prototype.hasOwnProperty.call(normalized.times, day))
        : [];
      normalized.interval = source.interval ? parseInt(source.interval, 10) : 30;
      if (!Number.isFinite(normalized.interval) || normalized.interval < 1) {
        normalized.interval = 30;
      }
      normalized.slots = source.slots ? parseInt(source.slots, 10) : 1;
      if (!Number.isFinite(normalized.slots) || normalized.slots < 1) {
        normalized.slots = 1;
      }

      Object.entries(source.times || {}).forEach(([day, blocks]) => {
        if (!Object.prototype.hasOwnProperty.call(normalized.times, day) || !Array.isArray(blocks)) {
          return;
        }

        normalized.times[day] = blocks
          .filter(block => block && typeof block === 'object')
          .map(block => ({
            from: String(block.from || '').replace(/:00$/, ''),
            to: String(block.to || '').replace(/:00$/, '')
          }))
          .filter(block => block.from && block.to);
      });

      return normalized;
    },
    normalizeScheduleMeta(payload) {
      const source = payload && typeof payload === 'object' ? payload : {};
      const guidanceSource = source.guidance && typeof source.guidance === 'object'
        ? source.guidance
        : {};
      const normalizeMinutes = (value) => {
        const parsed = parseInt(value, 10);
        if (!Number.isFinite(parsed) || parsed < 0) {
          return 0;
        }
        return parsed;
      };

      return {
        using_default_template: !!source.using_default_template,
        has_saved_schedule: !!source.has_saved_schedule,
        buffer_before_minutes: normalizeMinutes(source.buffer_before_minutes),
        buffer_after_minutes: normalizeMinutes(source.buffer_after_minutes),
        buffer_summary: typeof source.buffer_summary === 'string' ? source.buffer_summary : '',
        guidance: {
          title: typeof guidanceSource.title === 'string' ? guidanceSource.title : '',
          description: typeof guidanceSource.description === 'string' ? guidanceSource.description : '',
          items: Array.isArray(guidanceSource.items)
            ? guidanceSource.items.filter(item => typeof item === 'string' && item.trim() !== '')
            : []
        }
      };
    }
  },
  mounted() {
    this.updateFromHash();
    this.loadSetupDismissed();
    window.addEventListener('hashchange', this.updateFromHash);
  },
  beforeUnmount() {
    window.removeEventListener('hashchange', this.updateFromHash);
  }
};
</script>

<style scoped>
.cst-book-min-cont-hei {
  min-height:50vh;
}
@media (max-width:768px) {
  .bk-tab-cnt {
    display: none;
  }
}

.bk-tab-cnt a:focus,
.bk-tab-cnt a.text-blue-600{
  background: var(--bookaro-dashboard-accent);
  color: #fff;
}

.bk-tab-cnt a {
  padding-top: 10px;
}

.bk-nv-tb:hover {
  font-weight: bold;
}
.bk-nv-tb {
  flex: 1;
  font-size: 13px;
  text-align: center;
  font-weight: bold;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
}

aside > ul > li a {
  padding: 0 20px;
  color: #242429;
  font-weight: 600;
  line-height: 18px;
}
/* .spinner is defined in provider-dashboard-base.css */
</style>

