<template>
  <q-dialog
    ref="dialogRef"
    maximized
    transition-hide="slide-down"
    transition-show="slide-up"
  >
    <div class="dialog-root">
      <div
        class="dialog-header row items-center q-px-md q-pt-md q-pb-sm bg-white"
      >
        <q-btn
          v-close-popup
          class="header-back-btn"
          color="primary"
          dense
          flat
          icon="mdi-chevron-left"
          round
        />

        <div class="col text-center font16 fontbold gradient-diarista">
          {{ $t("scheduling_page.title") }}
        </div>

        <div style="width: 36px" />
      </div>

      <div class="dialog-body">
        <div class="q-px-md q-pt-md">
          <div class="info-banner card-border q-pa-md">
            <div class="font14 fontbold text-primary">
              {{ $t("scheduling_page.order_summary.info_text") }}
            </div>

            <div class="font12 fontmedium text-primary q-mt-xs">
              {{ $t("scheduling_page.order_summary.info_note") }}
            </div>
          </div>
        </div>

        <div class="q-px-md q-pt-md">
          <div class="font16 fontbold gradient-diarista q-mb-sm">
            {{ $t("scheduling_page.order_summary.title") }}
          </div>

          <q-card
            v-for="(booking, idx) in bookings"
            :key="idx"
            :flat="false"
            class="card-border bg-surface q-mb-sm shadow-card q-px-md q-pb-md"
          >
            <q-card-section class="q-pa-md row items-center no-wrap">
              <div class="col text-center">
                <div class="text-text">
                  <span class="font14 fontregular">
                    {{ $t("scheduling_page.order_summary.service_label") }}
                  </span>

                  <span class="font14 fontbold">
                    {{
                      ` ${booking.serviceType.label} (${booking.serviceType.hours})`
                    }}
                  </span>
                </div>

                <div class="font14 fontbold text-text">
                  {{ formatDate(booking.date) }}
                </div>

                <div class="font14 fontbold text-text">
                  {{
                    $t("scheduling_page.order_summary.time_range", {
                      start: booking.slot.startHour,
                      end: booking.slot.endHour,
                    })
                  }}
                </div>
              </div>

              <q-btn
                color="grey-5"
                dense
                flat
                icon="mdi-minus-circle-outline"
                padding="4px 8px"
                round
                @click="confirmRemove(idx)"
              />
            </q-card-section>

            <q-btn
              class="full-width q-mt-sm"
              color="secondary"
              no-caps
              padding="4px 8px"
              rounded
              unelevated
              :label="$t('scheduling_page.order_summary.send_btn')"
              @click="submitOrder"
            />
          </q-card>

          <div class="full-width text-center">
            <q-btn
              class="q-mt-xs"
              color="primary"
              no-caps
              outline
              rounded
              :disable="showCalendar"
              :label="$t('scheduling_page.order_summary.add_date_btn')"
              @click="showCalendar = true"
            />
          </div>
        </div>

        <div
          v-if="showCalendar"
          class="q-px-md q-pt-lg q-pb-xl"
        >
          <div
            v-if="loadingAvailability"
            class="row items-center justify-center q-py-lg"
          >
            <q-spinner-dots
              color="primary"
              size="36px"
            />
          </div>

          <div
            v-else
            class="calendar-wrapper shadow-card"
          >
            <q-date
              v-model="addDateValue"
              class=""
              color="purple"
              minimal
              :first-day-of-week="0"
              :options="dateOptions"
              @update:model-value="onAddDateSelected"
            />
          </div>
        </div>
      </div>
    </div>
  </q-dialog>
</template>

<script setup>
import { computed, onMounted, ref } from "vue";
import { createSchedule, getClientProviderBlocks } from "src/api/schedule";
import { date, useDialogPluginComponent, useQuasar } from "quasar";
import { getAddresses } from "src/api/address";

import {
  getProviderBlockedDays,
  getProviderWorkingDays,
} from "src/api/providerAvailability";

import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import { userStore } from "src/stores/user";
import { useServicePackageStore } from "src/stores/servicePackage";

import ServiceSelectionSheet from "./ServiceSelectionSheet.vue";
import ServiceTimeSelectionDialog from "./ServiceTimeSelectionDialog.vue";

defineEmits([...useDialogPluginComponent.emits]);

const props = defineProps({
  initialBooking: { required: true, type: Object },
  provider: { required: true, type: Object },
});

const { locale, t } = useI18n();
const router = useRouter();
const $q = useQuasar();
const { dialogRef, onDialogOK } = useDialogPluginComponent();

const servicePackage = useServicePackageStore();
const store = userStore();

const addDateValue = ref(null);
const blockedDays = ref([]);
const bookings = ref([props.initialBooking]);
const loadingAvailability = ref(false);
const primaryAddress = ref(null);

const providerClientBlocks = ref({
  existing_schedules: [],
  fully_blocked_weeks: [],
});

const showCalendar = ref(false);
const submitting = ref(false);
const workingDays = ref([]);

const availableWeekDays = computed(() => [
  ...new Set(workingDays.value.map((wd) => wd.day)),
]);

const blockedDateSet = computed(
  () =>
    new Set(
      blockedDays.value
        .filter((bd) => bd.period === "all")
        .map((bd) => bd.date),
    ),
);

const blockedWeekStartSet = computed(
  () => new Set(providerClientBlocks.value.fully_blocked_weeks ?? []),
);

const normalizeDate = (d) => d.replace(/\//g, "-");

const getWeekStart = (dateStr) => {
  const d = new Date(normalizeDate(dateStr) + "T12:00:00");

  d.setDate(d.getDate() - d.getDay());

  return d.toISOString().slice(0, 10);
};

const getServicePackageWeekCount = (newDateStr) => {
  const newWeek = getWeekStart(newDateStr);

  return servicePackage.items.filter(
    (item) =>
      Number(item.provider_id) === Number(props.provider.provider_id) &&
      getWeekStart(item.date) === newWeek,
  ).length;
};

const getLocalWeekCount = (newDateStr) => {
  const newWeek = getWeekStart(newDateStr);

  return bookings.value.filter(
    (booking) => getWeekStart(booking.date) === newWeek,
  ).length;
};

const getServerWeekCount = (newDateStr) => {
  const newWeek = getWeekStart(newDateStr);

  return (providerClientBlocks.value.existing_schedules ?? []).filter(
    (schedule) => getWeekStart(schedule.date) === newWeek,
  ).length;
};

const wouldExceedWeekLimit = (newDateStr) => {
  const count =
    getServerWeekCount(newDateStr) +
    getLocalWeekCount(newDateStr) +
    getServicePackageWeekCount(newDateStr);

  return count >= 2;
};

const confirmRemove = (idx) => {
  $q.dialog({
    title: t("scheduling_page.order_summary.remove_confirm_title"),
    cancel: {
      label: t("scheduling_page.order_summary.remove_confirm_cancel"),
      flat: true,
      color: "grey-6",
    },
    ok: {
      label: t("scheduling_page.order_summary.remove_confirm_ok"),
      unelevated: true,
      color: "primary",
      rounded: true,
      noCaps: true,
    },
    persistent: true,
  }).onOk(() => {
    bookings.value.splice(idx, 1);
  });
};

const dateOptions = (d) => {
  const today = date.formatDate(new Date(), "YYYY/MM/DD");

  if (d < today) return false;
  if (wouldExceedWeekLimit(d)) return false;

  const raw = normalizeDate(d);

  const parsed = new Date(`${raw}T12:00:00`);

  const dayOfWeek = parsed.getDay();
  const isWorking = availableWeekDays.value.includes(dayOfWeek);
  const isBlocked = blockedDateSet.value.has(raw);
  const isWeekBlocked = blockedWeekStartSet.value.has(getWeekStart(raw));

  return isWorking && !isBlocked && !isWeekBlocked;
};

const formatDate = (dateStr) => {
  const d = new Date(normalizeDate(dateStr) + "T12:00:00");

  const localeMap = { pt: "pt-BR", en: "en-US", es: "es-ES" };

  const loc = localeMap[locale.value] ?? "pt-BR";

  const weekday = new Intl.DateTimeFormat(loc, { weekday: "long" }).format(d);
  const dateFormatted = new Intl.DateTimeFormat(loc, {
    day: "2-digit",
    month: "2-digit",
    year: "numeric",
  }).format(d);

  return `${weekday.charAt(0).toUpperCase() + weekday.slice(1)}, ${dateFormatted}`;
};

const formatHour = (h) => `${String(h).padStart(2, "0")}:00`;

const loadAvailability = async () => {
  loadingAvailability.value = true;

  try {
    const clientId = store.user?.client_id;

    const defaultClientBlocks = {
      existing_schedules: [],
      fully_blocked_weeks: [],
    };

    const [wd, bd, clientBlocks] = await Promise.all([
      getProviderWorkingDays(props.provider.provider_id),
      getProviderBlockedDays(props.provider.provider_id),
      clientId
        ? getClientProviderBlocks(clientId, props.provider.provider_id)
        : Promise.resolve(defaultClientBlocks),
    ]);

    workingDays.value = wd ?? [];
    blockedDays.value = bd ?? [];

    providerClientBlocks.value = clientBlocks ?? defaultClientBlocks;
  } catch {
    workingDays.value = [];
    blockedDays.value = [];

    providerClientBlocks.value = {
      existing_schedules: [],
      fully_blocked_weeks: [],
    };
  } finally {
    loadingAvailability.value = false;
  }
};

const loadPrimaryAddress = async () => {
  try {
    const clientId = store.user?.client_id;

    if (!clientId) return;

    const addresses = await getAddresses("client", clientId);

    primaryAddress.value = (addresses ?? []).find((a) => a.is_primary) ?? null;
  } catch {
    primaryAddress.value = null;
  }
};

const onAddDateSelected = (val) => {
  if (!val) return;

  addDateValue.value = null;

  const valFormatted = normalizeDate(val);

  const blocksOfDate = blockedDays.value.filter(
    (bd) => bd.date === valFormatted && bd.period !== "all",
  );

  const dayOfWeek = new Date(`${valFormatted}T12:00:00`).getDay();

  const dayPeriods = workingDays.value
    .filter((wd) => wd.day === dayOfWeek)
    .map((wd) => wd.period);

  const workingDayBlocks = [];

  if (!dayPeriods.includes("afternoon")) {
    workingDayBlocks.push({ init_hour: "14:00:00", end_hour: "20:00:00" });
  }

  if (!dayPeriods.includes("morning")) {
    workingDayBlocks.push({ init_hour: "7:00:00", end_hour: "13:00:00" });
  }

  const existingBookingBlocks = bookings.value
    .filter((b) => b.date.replace(/\//g, "-") === valFormatted)
    .map((b) => ({
      init_hour: `${b.slot.startHour}:00:00`,
      end_hour: `${b.slot.endHour}:00:00`,
    }));

  const serverBookingBlocks = (
    providerClientBlocks.value.existing_schedules ?? []
  )
    .filter((schedule) => schedule.date === valFormatted)
    .map((schedule) => ({
      init_hour: schedule.start_time,
      end_hour: schedule.end_time,
    }));

  const servicePackageBookingBlocks = servicePackage.items
    .filter(
      (item) =>
        Number(item.provider_id) === Number(props.provider.provider_id) &&
        normalizeDate(item.date) === valFormatted,
    )
    .map((item) => ({
      init_hour: item.start_time,
      end_hour: item.end_time,
    }));

  const partialBlocks = [
    ...blocksOfDate,
    ...workingDayBlocks,
    ...existingBookingBlocks,
    ...serverBookingBlocks,
    ...servicePackageBookingBlocks,
  ];

  $q.dialog({
    component: ServiceSelectionSheet,
    componentProps: {
      provider: props.provider,
      selectedDate: val,
      partialBlocks,
    },
  }).onOk(({ serviceType, date: date_, provider: prov }) => {
    $q.dialog({
      component: ServiceTimeSelectionDialog,
      componentProps: {
        serviceType,
        selectedDate: date_,
        provider: prov,
        partialBlocks,
      },
    }).onOk((booking) => {
      if (wouldExceedWeekLimit(booking.date)) {
        $q.notify({
          type: "negative",
          message: t("scheduling_page.order_summary.week_limit_error"),
        });

        return;
      }

      bookings.value.push(booking);

      showCalendar.value = false;
    });
  });
};

const submitOrder = async () => {
  if (!primaryAddress.value) {
    $q.notify({
      type: "warning",
      message: t("scheduling_page.order_summary.no_primary_address"),
    });

    return;
  }

  const payloads = bookings.value.map((b) => ({
    client_id: store.user.client_id,
    provider_id: props.provider.provider_id,
    address_id: primaryAddress.value.id,
    schedule_type: "default",
    date: normalizeDate(b.date),
    period_type: b.serviceType.hoursCount,
    start_time: formatHour(b.slot.startHour),
    end_time: formatHour(b.slot.endHour),
    total_amount: b.serviceType.basePrice ?? b.serviceType.price,
    offers_meal:
      b.meal === "offer" ? true : b.meal === "no_offer" ? false : null,
  }));

  submitting.value = true;

  try {
    await Promise.all(payloads.map((payload) => createSchedule(payload)));

    $q.notify({
      type: "positive",
      message: t("scheduling_page.order_summary.submit_success"),
    });

    onDialogOK();
  } catch (err) {
    const msg =
      err?.response?.data?.message ??
      err?.message ??
      t("scheduling_page.order_summary.submit_error");

    $q.notify({ type: "negative", message: msg });
  } finally {
    submitting.value = false;

    router.push({ name: "DashboardPage" });
  }
};

onMounted(() => Promise.all([loadAvailability(), loadPrimaryAddress()]));
</script>

<style scoped lang="scss">
.dialog-root {
  width: 100vw;
  max-width: 100vw;
  height: 100vh;
  max-height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #f9fafb;
}

.dialog-header {
  flex-shrink: 0;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

.dialog-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: clip;
}

.info-banner {
  background: rgba(139, 92, 246, 0.08);
  border: 1px solid rgba(139, 92, 246, 0.2);
}

.calendar-wrapper {
  border-radius: 20px;
  overflow: hidden;
  background: white;

  :deep(.q-date) {
    background: white;
    width: 100%;
  }
  :deep(.q-date__main),
  :deep(.q-date__content),
  :deep(.q-date__calendar) {
    background: white !important;
  }

  :deep(.q-date__calendar-item .q-btn) {
    min-width: 0 !important;
    padding: 6px 2px !important;
  }
  :deep(.q-date__calendar-item .q-btn.disabled),
  :deep(.q-date__calendar-item .q-btn[disabled]) {
    opacity: 1 !important;
  }
  :deep(.q-date__calendar-item .q-btn.disabled .q-btn__content),
  :deep(.q-date__calendar-item .q-btn[disabled] .q-btn__content) {
    color: #cbd5e1 !important;
  }

  :deep(.q-date__calendar-days .q-btn__content) {
    font-weight: 500;
    color: #1e293b;
  }
  :deep(.q-date__calendar-weekdays > div) {
    color: #6366f1;
    font-weight: 700;
    opacity: 0.8;
  }
  :deep(.q-date__navigation) {
    .q-btn {
      color: #6366f1 !important;
    }
    .q-btn__content {
      color: #6366f1 !important;
    }
  }
  :deep(.q-date__event) {
    bottom: 4px;
    height: 6px;
    width: 6px;
    border-radius: 50%;
  }
  :deep(.q-date__today .q-btn__content) {
    color: #7c4dff !important;
    background: #7c4dff15;
    border-radius: 50%;
  }
  :deep(.q-date__selected .q-btn__content) {
    background: #6366f1 !important;
    color: white !important;
    border-radius: 50%;
    box-shadow: 0 4px 10px rgba(99, 102, 241, 0.4);
  }
}

.calendar-custom {
  border-radius: 20px;
  background-color: white !important;

  :deep(.q-date__main) {
    background-color: white !important;
  }

  :deep(.q-date__content) {
    background-color: white !important;
  }

  :deep(.q-date__calendar) {
    background-color: white !important;
  }

  :deep(.q-date__calendar-item--out) {
    .q-btn__content {
      color: #cbd5e1 !important;
    }
  }

  :deep(.q-date__calendar-days .q-btn__content) {
    font-weight: 500;
    color: #1e293b;
  }

  :deep(.q-date__calendar-weekdays > div) {
    color: #6366f1;
    font-weight: 700;
    opacity: 0.8;
  }

  :deep(.q-date__navigation) {
    .q-btn {
      color: #1e293b !important;
    }
    .q-btn__content {
      color: #1e293b !important;
    }
  }

  :deep(.q-date__nav-btn-month),
  :deep(.q-date__nav-btn-year) {
    color: #6366f1 !important;
    font-weight: 700;
  }

  :deep(.q-date__event) {
    bottom: 4px;
    height: 6px;
    width: 6px;
    border-radius: 50%;
  }

  :deep(.q-date__today) {
    .q-btn__content {
      color: #7c4dff !important;
      background: #7c4dff15;
      border-radius: 50%;
    }
  }

  :deep(.q-date__selected) {
    .q-btn__content {
      background: #6366f1 !important;
      color: white !important;
      border-radius: 50%;
      box-shadow: 0 4px 10px rgba(99, 102, 241, 0.4);
    }
  }

  :deep(.q-date__view--months),
  :deep(.q-date__view--years) {
    .q-btn {
      color: #1e293b !important;
    }
  }
}
</style>
