<template>
  <q-dialog ref="dialogRef" @hide="onDialogHide">
    <div style="width: 100%; max-width: 560px">
      <q-card class="dialog-form-card">
        <DefaultDialogHeader
          :title="classData ? 'Editar Aula' : 'Nova Aula'"
          @close="onDialogCancel"
        />

        <DefaultForm ref="formRef" @submit="onSubmit">
          <q-scroll-area
            ref="scrollAreaRef"
            class="dialog-form-scroll dialog-form-scroll--md"
          >
            <q-card-section class="q-pt-sm">
              <div class="row q-col-gutter-sm">
                <DefaultInput
                  v-model="form.title"
                  v-model:error="validationErrors.title"
                  class="col-12"
                  label="Nome da Atividade"
                  :rules="titleRules"
                />

                <DefaultSelect
                  v-model="form.class_package_unit_id"
                  v-model:error="validationErrors.class_package_unit_id"
                  label="Pacote relacionado"
                  class="col-12"
                  emit-value
                  map-options
                  option-label="name"
                  option-value="id"
                  :loading="loadingPackages"
                  :options="packageOptions"
                  :rules="packageRules"
                />

                <DefaultInput
                  v-model="form.start_time"
                  v-model:error="validationErrors.date_time_start"
                  class="col-6"
                  label="Hora de Início"
                  mask="##:##"
                  placeholder="08:40"
                  :rules="startTimeRules"
                >
                  <template #append>
                    <q-icon
                      class="cursor-pointer"
                      color="secondary"
                      name="mdi-clock-outline"
                    >
                      <q-popup-proxy
                        transition-hide="scale"
                        transition-show="scale"
                      >
                        <q-time
                          v-model="form.start_time"
                          format24h
                          mask="HH:mm"
                        >
                          <div class="row items-center justify-end">
                            <q-btn
                              v-close-popup
                              color="primary"
                              label="OK"
                              flat
                            />
                          </div>
                        </q-time>
                      </q-popup-proxy>
                    </q-icon>
                  </template>
                </DefaultInput>

                <DefaultInput
                  v-model="form.end_time"
                  v-model:error="validationErrors.date_time_end"
                  class="col-6"
                  label="Hora de Fim"
                  mask="##:##"
                  placeholder="09:40"
                  :rules="endTimeRules"
                >
                  <template #append>
                    <q-icon
                      class="cursor-pointer"
                      color="secondary"
                      name="mdi-clock-outline"
                    >
                      <q-popup-proxy
                        transition-hide="scale"
                        transition-show="scale"
                      >
                        <q-time v-model="form.end_time" format24h mask="HH:mm">
                          <div class="row items-center justify-end">
                            <q-btn
                              v-close-popup
                              color="primary"
                              flat
                              label="OK"
                            />
                          </div>
                        </q-time>
                      </q-popup-proxy>
                    </q-icon>
                  </template>
                </DefaultInput>

                <DefaultSelect
                  v-model="form.instructor"
                  v-model:error="validationErrors.instructor"
                  class="col-6"
                  clearable
                  emit-value
                  label="Neurotrainer"
                  map-options
                  option-label="name"
                  option-value="name"
                  :loading="loadingInstructors"
                  :options="instructorOptions"
                  :rules="[optionalMaxLengthRule(255)]"
                />

                <DefaultInput
                  v-model="form.room"
                  v-model:error="validationErrors.room"
                  class="col-6"
                  label="Número da Sala"
                  :rules="[optionalMaxLengthRule(255)]"
                />

                <DefaultInputDatePicker
                  v-model="form.date_display"
                  v-model:error="validationErrors.date_time_start"
                  v-model:untreated-date="form.date"
                  class="col-12"
                  label="Data de Início"
                  :rules="dateRules"
                />
              </div>
            </q-card-section>
          </q-scroll-area>

          <q-card-actions align="right" class="q-px-md q-pb-md">
            <q-btn
              color="primary"
              label="Cancelar"
              no-caps
              outline
              @click="onDialogCancel"
            />

            <q-btn
              color="primary"
              label="Salvar"
              no-caps
              type="submit"
              :loading="saving"
            />
          </q-card-actions>
        </DefaultForm>
      </q-card>
    </div>
  </q-dialog>
</template>

<script setup>
import { createClass, updateClass } from "src/api/class";
import { getUnitPackagesForSelect } from "src/api/package";
import { getUsersByUnit } from "src/api/user";
import { format, isValid, parse } from "date-fns";
import { onMounted, ref, useTemplateRef, watch } from "vue";
import { useDialogPluginComponent, useQuasar } from "quasar";
import { useForm } from "src/composables/useForm";
import { useInputRules } from "src/composables/useInputRules";
import { useScroll } from "src/composables/useScroll";
import { useSubmitHandler } from "src/composables/useSubmitHandler";

import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
import DefaultInput from "src/components/defaults/DefaultInput.vue";
import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";

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

const props = defineProps({
  classData: { type: Object, default: null },
  // Data pré-selecionada ao adicionar a partir de um dia do calendário (YYYY-MM-DD)
  initialDate: { type: String, default: null },
});

const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
  useDialogPluginComponent();

const $q = useQuasar();
const { inputRules } = useInputRules();
const { scrollToComponent } = useScroll();

const formRef = useTemplateRef("formRef");
const scrollAreaRef = useTemplateRef("scrollAreaRef");

const loadingPackages = ref(false);
const packageOptions = ref([]);
const loadingInstructors = ref(false);
const instructorOptions = ref([]);

const toDisplay = (isoDate) =>
  isoDate ? isoDate.split("-").reverse().join("/") : null;

const { form, getUpdatedFields } = useForm({
  title: props.classData?.title ?? "",
  class_package_unit_id: props.classData?.class_package_unit_id ?? null,
  instructor: props.classData?.instructor ?? "",
  room: props.classData?.room ?? "",
  start_time: props.classData?.date_time_start?.slice(11, 16) ?? "",
  end_time: props.classData?.date_time_end?.slice(11, 16) ?? "",

  date: props.classData?.date_time_start?.slice(0, 10) ?? props.initialDate ?? null,

  date_display: toDisplay(
    props.classData?.date_time_start?.slice(0, 10) ?? props.initialDate,
  ),
});

const emptyOptionalValue = (value) => value == null || value === "";

const endAfterStartRule = (value) =>
  !form.start_time ||
  !value ||
  value > form.start_time ||
  "Fim deve ser após o início.";

const integerRule = (value) =>
  emptyOptionalValue(value) ||
  Number.isInteger(Number(value)) ||
  "Informe um número inteiro válido.";

const optionalMaxLengthRule = (max) => (value) =>
  emptyOptionalValue(value) ||
  String(value).length <= max ||
  `Informe no máximo ${max} caracteres.`;

const validDateRule = (value) => {
  if (emptyOptionalValue(value)) return true;

  const parsedDate = parse(value, "dd/MM/yyyy", new Date());

  return (
    (isValid(parsedDate) && format(parsedDate, "dd/MM/yyyy") === value) ||
    "Informe uma data válida."
  );
};

const validTimeRule = (value) => {
  if (emptyOptionalValue(value)) return true;

  const match = /^(\d{2}):(\d{2})$/.exec(value);

  return (
    (!!match && Number(match[1]) <= 23 && Number(match[2]) <= 59) ||
    "Informe um horário válido."
  );
};

const titleRules = [inputRules.required, optionalMaxLengthRule(255)];
const packageRules = [inputRules.required, integerRule];
const startTimeRules = [inputRules.required, validTimeRule];
const endTimeRules = [inputRules.required, validTimeRule, endAfterStartRule];
const dateRules = [inputRules.required, validDateRule];

const trimTime = (time) => (time ? time.slice(0, 5) : "");

const applyPackageSchedule = () => {
  if (props.classData) return;

  const pkg = selectedPackage();

  if (!pkg) return;

  const selectedWeekday = form.date
    ? new Date(`${form.date}T00:00:00`).getDay()
    : null;

  const startTime =
    selectedWeekday === pkg.second_weekday
      ? pkg.second_start_time
      : pkg.start_time;

  if (!startTime) return;

  form.start_time = trimTime(startTime);

  form.end_time = calculateEndTime(
    form.start_time,
    pkg.class_duration_minutes ?? 120,
  );
}

const calculateEndTime = (startTime, durationMinutes = 120) => {
  if (!/^\d{2}:\d{2}$/.test(startTime ?? "")) return "";

  const [hours, minutes] = startTime.split(":").map(Number);

  if (hours > 23 || minutes > 59) return "";

  const endMinutes = (hours * 60 + minutes + durationMinutes) % (24 * 60);

  return `${String(Math.floor(endMinutes / 60)).padStart(2, "0")}:${String(
    endMinutes % 60,
  ).padStart(2, "0")}`;
}

const selectedPackage = () => {
  return packageOptions.value.find(
    (pkg) => pkg.id === form.class_package_unit_id,
  );
}

//

const loadInstructors = async () => {
  loadingInstructors.value = true;

  try {
    const users = await getUsersByUnit();

    instructorOptions.value = (users ?? []).filter(
      (u) =>
        u.user_type_system_key === "NEUROTRAINER" ||
        u.user_type === "NEUROTRAINER" ||
        u.user_type_label?.trim().toUpperCase() === "NEUROTRAINER",
    );
  } catch (e) {
    console.error("Erro ao carregar neurotrainers:", e);
  } finally {
    loadingInstructors.value = false;
  }
};

const loadPackages = async () => {
  loadingPackages.value = true;

  try {
    packageOptions.value = await getUnitPackagesForSelect();
  } finally {
    loadingPackages.value = false;
  }
};

//

const {
  loading: saving,
  validationErrors,
  execute,
} = useSubmitHandler({
  formRef,
  containerRef: scrollAreaRef,
  scrollFn: scrollToComponent,
  onSuccess: () => {
    $q.notify({ type: "positive", message: "Aula salva com sucesso." });
    onDialogOK(true);
  },
});

const onSubmit = async () => {
  const payload = {
    title: form.title,
    class_package_unit_id: form.class_package_unit_id,
    instructor: form.instructor || null,
    room: form.room || null,
    date_time_start: `${form.date}T${form.start_time}:00`,
    date_time_end: `${form.date}T${form.end_time}:00`,
  };

  await execute(() => {
    if (!props.classData?.id) return createClass(payload);

    const changed = getUpdatedFields.value;

    const updatePayload = {};

    for (const key of [
      "title",
      "class_package_unit_id",
      "instructor",
      "room",
    ]) {
      if (key in changed) updatePayload[key] = payload[key];
    }

    if ("date" in changed || "start_time" in changed) {
      updatePayload.date_time_start = payload.date_time_start;
    }

    if ("date" in changed || "end_time" in changed) {
      updatePayload.date_time_end = payload.date_time_end;
    }

    return updateClass(updatePayload, props.classData.id);
  });
};

watch(() => form.class_package_unit_id, applyPackageSchedule);

watch(
  () => form.date,
  () => {
    if (!form.start_time) applyPackageSchedule();
  },
);

watch(
  () => form.start_time,
  (startTime) => {
    const endTime = calculateEndTime(
      startTime,
      selectedPackage()?.class_duration_minutes ?? 120,
    );

    if (endTime) form.end_time = endTime;
  },
);

onMounted(() => {
  loadPackages();
  loadInstructors();
});
</script>
