<template>
  <q-dialog ref="dialogRef" @hide="onDialogHide">
    <q-card
      class="q-dialog-plugin dialog-form-card"
      style="width: 100%; max-width: 1100px"
    >
      <DefaultDialogHeader
        title="Cadastrar Aluno"
        @close="onDialogCancel"
      />

      <DefaultForm
        ref="formRef"
        @submit="onOKClick"
      >
        <q-scroll-area
          ref="scrollAreaRef"
          class="dialog-form-scroll"
        >
          <q-card-section class="q-pt-sm">
            <CustomTabComponent
              :active-tab="activeTab"
              :tabs="tabs"
              class="q-mb-md"
              @update:active-tab="handleTabChange"
            />

            <div
              v-show="activeTab === 'student'"
              ref="studentTabRef"
            >
              <q-banner
                v-if="validationErrors.registration_draft_token"
                class="bg-red-1 text-negative q-mb-md"
                rounded
              >
                {{ validationErrors.registration_draft_token }}
              </q-banner>

              <div class="flex justify-center q-mb-md">
                <AvatarImageComponent
                  ref="avatarRef"
                  @update:file="onAvatarChange"
                />
              </div>

              <div class="row q-col-gutter-sm">
                <DefaultInput
                  v-model="form.name"
                  class="col-6"
                  label="Nome do Aluno"
                  :error="!!validationErrors.name"
                  :error-message="validationErrors.name"
                  :rules="[inputRules.required]"
                />

                <DefaultInputDatePicker
                  v-model="form.birthdate"
                  class="col-6"
                  label="Data de Nascimento"
                  :error="!!validationErrors.birth_date"
                  :error-message="validationErrors.birth_date"
                  :rules="[inputRules.required]"
                />

                <DefaultInput
                  v-model="form.cpf"
                  class="col-6"
                  label="CPF"
                  :error="!!validationErrors.document_number"
                  :error-message="validationErrors.document_number"
                  :mask="masks.Brasil.cpf"
                  :rules="[inputRules.cpf]"
                />

                <DefaultSelect
                  v-model="form.gender"
                  class="col-6"
                  emit-value
                  label="Gênero"
                  map-options
                  :error="!!validationErrors.gender"
                  :error-message="validationErrors.gender"
                  :options="genderOptions"
                />

                <DefaultInput
                  v-model="form.email"
                  class="col-6"
                  label="E-mail"
                  type="email"
                  :error="!!validationErrors.email"
                  :error-message="validationErrors.email"
                  :rules="[inputRules.email]"
                />

                <DefaultInput
                  v-model="form.phone"
                  class="col-6"
                  label="Celular com DDD"
                  :error="!!validationErrors.phone"
                  :error-message="validationErrors.phone"
                  :mask="masks.Brasil.celular"
                />

                <DefaultCepInput
                  v-model="form.cep"
                  class="col-4"
                  :error="!!validationErrors.postal_code"
                  :error-message="validationErrors.postal_code"
                  :rules="[inputRules.cep]"
                  @bairro="(value) => (form.neighborhood = value)"
                  @cidade="
                    (value) =>
                      citySelectRef?.selectCityByName(value)
                  "
                  @rua="(value) => (form.address = value)"
                  @uf="
                    (value) =>
                      stateSelectRef?.selectStateByCode(value)
                  "
                />

                <DefaultInput
                  v-model="form.address"
                  class="col-5"
                  label="Endereço"
                  :error="!!validationErrors.street"
                  :error-message="validationErrors.street"
                />

                <DefaultInput
                  v-model="form.address_number"
                  class="col-3"
                  label="Número"
                  :error="!!validationErrors.address_number"
                  :error-message="validationErrors.address_number"
                />

                <DefaultInput
                  v-model="form.neighborhood"
                  class="col-4"
                  label="Bairro"
                  :error="!!validationErrors.neighborhood"
                  :error-message="validationErrors.neighborhood"
                />

                <CitySelect
                  ref="citySelectRef"
                  v-model="selectedCity"
                  class="col-4"
                  label="Cidade"
                  :error="!!validationErrors.city_id"
                  :error-message="validationErrors.city_id"
                  :state="selectedState"
                />

                <StateSelect
                  ref="stateSelectRef"
                  v-model="selectedState"
                  class="col-4"
                  label="Estado"
                  :error="!!validationErrors.state_id"
                  :error-message="validationErrors.state_id"
                />

                <DefaultInput
                  v-model="form.complement"
                  class="col-6"
                  label="Complemento"
                  :error="!!validationErrors.complement"
                  :error-message="validationErrors.complement"
                />

                <DefaultInput
                  v-model="form.payer"
                  class="col-6"
                  label="Pagador"
                  :error="!!validationErrors.payer_name"
                  :error-message="validationErrors.payer_name"
                />

                <DefaultSelect
                  v-model="form.how_found"
                  class="col-12"
                  emit-value
                  label="Como nos conheceu?"
                  map-options
                  :error="!!validationErrors.how_did_you_know_us"
                  :error-message="
                    validationErrors.how_did_you_know_us
                  "
                  :options="howFoundOptions"
                />

                <DefaultInput
                  v-model="form.notes"
                  autogrow
                  class="col-12"
                  label="Observações"
                  type="textarea"
                  :error="!!validationErrors.notes"
                  :error-message="validationErrors.notes"
                  :input-style="{ minHeight: '120px' }"
                />
              </div>
            </div>

            <div
              v-if="isStudentUnderage"
              v-show="activeTab === 'responsible'"
              ref="responsibleTabRef"
            >
              <q-banner
                class="bg-orange-1 text-orange-10 q-mb-md"
                rounded
              >
                O aluno é menor de 18 anos. Cadastre um responsável para
                concluir.
              </q-banner>

              <div class="row q-col-gutter-sm">
                <DefaultInput
                  v-model="responsibleForm.name"
                  class="col-6"
                  label="Nome"
                  :error="!!validationErrors['responsible.name']"
                  :error-message="
                    validationErrors['responsible.name']
                  "
                  :rules="
                    activeTab === 'responsible'
                      ? [inputRules.required]
                      : []
                  "
                />

                <DefaultInput
                  v-model="responsibleForm.degree"
                  class="col-6"
                  label="Grau de Parentesco"
                  :error="!!validationErrors['responsible.degree']"
                  :error-message="
                    validationErrors['responsible.degree']
                  "
                  :rules="responsibleRequiredRules"
                />

                <DefaultInputDatePicker
                  v-model="responsibleForm.birth_date"
                  class="col-4"
                  label="Data de Nascimento"
                  :error="
                    !!validationErrors['responsible.birth_date']
                  "
                  :error-message="
                    validationErrors['responsible.birth_date']
                  "
                  :rules="responsibleRequiredRules"
                />

                <DefaultInput
                  v-model="responsibleForm.cpf"
                  class="col-4"
                  label="CPF"
                  :error="!!validationErrors['responsible.cpf']"
                  :error-message="
                    validationErrors['responsible.cpf']
                  "
                  :mask="masks.Brasil.cpf"
                  :rules="
                    activeTab === 'responsible'
                      ? [inputRules.required, inputRules.cpf]
                      : []
                  "
                />

                <DefaultSelect
                  v-model="responsibleForm.gender"
                  class="col-4"
                  emit-value
                  label="Gênero"
                  map-options
                  :error="!!validationErrors['responsible.gender']"
                  :error-message="
                    validationErrors['responsible.gender']
                  "
                  :options="genderOptions"
                />

                <DefaultInput
                  v-model="responsibleForm.email"
                  class="col-6"
                  label="E-mail"
                  type="email"
                  :error="!!validationErrors['responsible.email']"
                  :error-message="
                    validationErrors['responsible.email']
                  "
                  :rules="responsibleEmailRules"
                />

                <DefaultInput
                  v-model="responsibleForm.phone"
                  class="col-6"
                  label="Telefone"
                  :error="!!validationErrors['responsible.phone']"
                  :error-message="
                    validationErrors['responsible.phone']
                  "
                  :mask="masks.Brasil.celular"
                  :rules="responsibleRequiredRules"
                />

                <DefaultCepInput
                  v-model="responsibleForm.postal_code"
                  class="col-4"
                  :error="
                    !!validationErrors['responsible.postal_code']
                  "
                  :error-message="
                    validationErrors['responsible.postal_code']
                  "
                  :rules="responsibleCepRules"
                  @bairro="
                    (value) =>
                      (responsibleForm.neighborhood = value)
                  "
                  @cidade="
                    (value) =>
                      responsibleCitySelectRef?.selectCityByName(
                        value,
                      )
                  "
                  @rua="
                    (value) =>
                      (responsibleForm.street = value)
                  "
                  @uf="
                    (value) =>
                      responsibleStateSelectRef?.selectStateByCode(
                        value,
                      )
                  "
                />

                <DefaultInput
                  v-model="responsibleForm.street"
                  class="col-5"
                  label="Endereço"
                  :error="!!validationErrors['responsible.street']"
                  :error-message="
                    validationErrors['responsible.street']
                  "
                  :rules="responsibleRequiredRules"
                />

                <DefaultInput
                  v-model="responsibleForm.address_number"
                  class="col-3"
                  label="Número"
                  :error="
                    !!validationErrors[
                      'responsible.address_number'
                    ]
                  "
                  :error-message="
                    validationErrors[
                      'responsible.address_number'
                    ]
                  "
                />

                <DefaultInput
                  v-model="responsibleForm.neighborhood"
                  class="col-4"
                  label="Bairro"
                  :error="
                    !!validationErrors[
                      'responsible.neighborhood'
                    ]
                  "
                  :error-message="
                    validationErrors[
                      'responsible.neighborhood'
                    ]
                  "
                  :rules="responsibleRequiredRules"
                />

                <CitySelect
                  ref="responsibleCitySelectRef"
                  v-model="responsibleSelectedCity"
                  class="col-4"
                  label="Cidade"
                  :error="
                    !!validationErrors['responsible.city_id']
                  "
                  :error-message="
                    validationErrors['responsible.city_id']
                  "
                  :rules="responsibleRequiredRules"
                  :state="responsibleSelectedState"
                />

                <StateSelect
                  ref="responsibleStateSelectRef"
                  v-model="responsibleSelectedState"
                  class="col-4"
                  label="Estado"
                  :error="
                    !!validationErrors['responsible.state_id']
                  "
                  :error-message="
                    validationErrors['responsible.state_id']
                  "
                  :rules="responsibleRequiredRules"
                />

                <DefaultInput
                  v-model="responsibleForm.complement"
                  class="col-12"
                  label="Complemento"
                  :error="
                    !!validationErrors['responsible.complement']
                  "
                  :error-message="
                    validationErrors['responsible.complement']
                  "
                />

                <DefaultInput
                  v-model="responsibleForm.notes"
                  autogrow
                  class="col-12"
                  label="Observações"
                  type="textarea"
                  :error="!!validationErrors['responsible.notes']"
                  :error-message="
                    validationErrors['responsible.notes']
                  "
                  :input-style="{ minHeight: '120px' }"
                />
              </div>
            </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"
            no-caps
            type="submit"
            :label="primaryActionLabel"
            :loading="loading"
          />
        </q-card-actions>
      </DefaultForm>
    </q-card>
  </q-dialog>
</template>

<script setup>
import {
  computed,
  nextTick,
  ref,
  useTemplateRef,
  watch,
} from "vue";

import {
  createStudent,
  createStudentRegistrationDraft,
} from "src/api/student";

import {
  formatDateDMYtoYMD,
  isUnderage,
} from "src/helpers/utils";

import { useDialogPluginComponent } from "quasar";
import { useInputRules } from "src/composables/useInputRules";
import { useScroll } from "src/composables/useScroll";
import { useSubmitHandler } from "src/composables/useSubmitHandler";

import masks from "src/helpers/masks";

import DefaultCepInput from "src/components/defaults/DefaultCepInput.vue";
import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
import DefaultForm from "src/components/defaults/DefaultForm.vue";
import DefaultInput from "src/components/defaults/DefaultInput.vue";
import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
import CitySelect from "src/components/selects/CitySelect.vue";
import StateSelect from "src/components/selects/StateSelect.vue";
import AvatarImageComponent from "src/components/shared/AvatarImageComponent.vue";
import CustomTabComponent from "src/components/shared/CustomTabComponent.vue";

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

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

const { inputRules } = useInputRules();
const { scrollToComponent } = useScroll();

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

const responsibleCitySelectRef = useTemplateRef(
  "responsibleCitySelectRef",
);

const responsibleStateSelectRef = useTemplateRef(
  "responsibleStateSelectRef",
);

const responsibleTabRef = useTemplateRef("responsibleTabRef");
const scrollAreaRef = useTemplateRef("scrollAreaRef");
const stateSelectRef = useTemplateRef("stateSelectRef");
const studentTabRef = useTemplateRef("studentTabRef");

const activeTab = ref("student");
const avatarFile = ref(null);
const registrationDraftToken = ref(null);
const responsibleSelectedCity = ref(null);
const responsibleSelectedState = ref(null);
const selectedCity = ref(null);
const selectedState = ref(null);

const form = ref({
  address: null,
  address_number: null,
  birthdate: null,
  cep: null,
  city_id: null,
  complement: null,
  cpf: null,
  email: null,
  gender: "no_preference",
  how_found: null,
  name: null,
  neighborhood: null,
  notes: null,
  payer: null,
  phone: null,
  state_id: null,
});

const responsibleForm = ref({
  address_number: null,
  birth_date: null,
  city_id: null,
  complement: null,
  cpf: null,
  degree: null,
  email: null,
  gender: "no_preference",
  name: null,
  neighborhood: null,
  notes: null,
  phone: null,
  postal_code: null,
  state_id: null,
  street: null,
});

const isStudentUnderage = computed(() =>
  isUnderage(form.value.birthdate),
);

const responsibleCepRules = computed(() =>
  activeTab.value === "responsible"
    ? [inputRules.required, inputRules.cep]
    : [inputRules.cep],
);

const responsibleEmailRules = computed(() =>
  activeTab.value === "responsible"
    ? [inputRules.required, inputRules.email]
    : [inputRules.email],
);

const responsibleRequiredRules = computed(() =>
  activeTab.value === "responsible"
    ? [inputRules.required]
    : [],
);

const tabs = computed(() => [
  {
    label: "Dados do Aluno",
    name: "student",
  },
  ...(isStudentUnderage.value
    ? [
        {
          label: "Responsável",
          name: "responsible",
        },
      ]
    : []),
]);

const primaryActionLabel = computed(() =>
  isStudentUnderage.value &&
  activeTab.value === "student"
    ? "Próximo"
    : "Cadastrar",
);

const genderOptions = [
  {
    label: "Prefiro não informar",
    value: "no_preference",
  },
  {
    label: "Masculino",
    value: "male",
  },
  {
    label: "Feminino",
    value: "female",
  },
  {
    label: "Outro",
    value: "other",
  },
];

const howFoundOptions = [
  {
    label: "Indicação",
    value: "referral",
  },
  {
    label: "Redes Sociais",
    value: "social_media",
  },
  {
    label: "Google",
    value: "google",
  },
  {
    label: "Outro",
    value: "other",
  },
];

const REGISTRATION_DRAFT_TOKEN_STORAGE_KEY =
  "student_registration_draft_token";

localStorage.removeItem(
  REGISTRATION_DRAFT_TOKEN_STORAGE_KEY,
);

const scrollToTabError = async (
  component,
  container,
  options,
) => {
  const element = component?.$el ?? component;

  const studentElement =
    studentTabRef.value?.$el ?? studentTabRef.value;

  const responsibleElement =
    responsibleTabRef.value?.$el ??
    responsibleTabRef.value;

  if (studentElement?.contains(element)) {
    await setActiveTab("student");
  } else if (responsibleElement?.contains(element)) {
    await setActiveTab("responsible");
  }

  return scrollToComponent(
    component,
    container,
    options,
  );
};

const {
  loading: saving,
  validationErrors: submitValidationErrors,
  execute: executeSubmit,
} = useSubmitHandler({
  containerRef: scrollAreaRef,
  formRef,
  onSuccess: (student) => {
    clearRegistrationDraftToken();
    onDialogOK(student);
  },
  scrollFn: scrollToTabError,
});

const {
  loading: validatingStudent,
  validationErrors: draftValidationErrors,
  execute: executeDraft,
} = useSubmitHandler({
  containerRef: scrollAreaRef,
  formRef,
  scrollFn: scrollToTabError,
});

const loading = computed(
  () => saving.value || validatingStudent.value,
);

const validationErrors = computed(() => ({
  ...draftValidationErrors.value,
  ...submitValidationErrors.value,
}));

const appendResponsibleToFormData = (formData) => {
  const responsible = buildResponsiblePayload();

  Object.entries(responsible).forEach(([field, value]) => {
    formData.append(
      `responsible[${field}]`,
      value ?? "",
    );
  });
};

const appendStudentToFormData = (formData) => {
  const student = buildStudentPayload();

  Object.entries(student).forEach(([field, value]) => {
    formData.append(field, value ?? "");
  });
};

const buildPayload = () => {
  if (isStudentUnderage.value) {
    if (avatarFile.value) {
      const formData = new FormData();

      appendStudentToFormData(formData);

      formData.append(
        "registration_draft_token",
        registrationDraftToken.value,
      );

      formData.append("avatar", avatarFile.value);

      appendResponsibleToFormData(formData);

      return formData;
    }

    return {
      ...buildStudentPayload(),
      registration_draft_token:
        registrationDraftToken.value,
      responsible: buildResponsiblePayload(),
    };
  }

  if (avatarFile.value) {
    const formData = new FormData();

    appendStudentToFormData(formData);
    formData.append("avatar", avatarFile.value);

    return formData;
  }

  return buildStudentPayload();
};

const buildRegistrationDraftPayload = () => ({
  birth_date: form.value.birthdate
    ? formatDateDMYtoYMD(form.value.birthdate)
    : null,

  document_number: form.value.cpf,
  email: form.value.email || null,
  name: form.value.name,

  registration_draft_token:
    registrationDraftToken.value,
});

const buildResponsiblePayload = () => ({
  address_number: responsibleForm.value.address_number,

  birth_date: responsibleForm.value.birth_date
    ? formatDateDMYtoYMD(
        responsibleForm.value.birth_date,
      )
    : null,

  city_id: responsibleForm.value.city_id,
  complement: responsibleForm.value.complement,
  cpf: responsibleForm.value.cpf,
  degree: responsibleForm.value.degree,
  email: responsibleForm.value.email || null,
  gender: responsibleForm.value.gender,
  name: responsibleForm.value.name,
  neighborhood: responsibleForm.value.neighborhood,
  notes: responsibleForm.value.notes,
  phone: responsibleForm.value.phone,
  postal_code: responsibleForm.value.postal_code,
  state_id: responsibleForm.value.state_id,
  street: responsibleForm.value.street,
});

const buildStudentPayload = () => ({
  address_number: form.value.address_number,

  birth_date: form.value.birthdate
    ? formatDateDMYtoYMD(form.value.birthdate)
    : null,

  city_id: form.value.city_id,
  complement: form.value.complement,
  document_number: form.value.cpf,
  email: form.value.email || null,
  gender: form.value.gender,
  how_did_you_know_us: form.value.how_found,
  name: form.value.name,
  neighborhood: form.value.neighborhood,
  notes: form.value.notes,
  payer_name: form.value.payer,
  phone: form.value.phone,
  postal_code: form.value.cep,
  state_id: form.value.state_id,
  street: form.value.address,
});

const clearRegistrationDraftToken = () => {
  registrationDraftToken.value = null;

  localStorage.removeItem(
    REGISTRATION_DRAFT_TOKEN_STORAGE_KEY,
  );
};

const goToResponsible = async () => {
  if (validatingStudent.value) return;

  const createDraft = () =>
    createStudentRegistrationDraft(
      buildRegistrationDraftPayload(),
    );

  let draft;

  try {
    draft = await executeDraft(createDraft);
  } catch (error) {
    const draftTokenError =
      draftValidationErrors.value
        .registration_draft_token;

    if (
      !draftTokenError ||
      !registrationDraftToken.value
    ) {
      throw error;
    }

    clearRegistrationDraftToken();

    draft = await executeDraft(createDraft);
  }

  const nextToken = draft?.registration_draft_token;

  if (
    nextToken &&
    nextToken !== registrationDraftToken.value
  ) {
    saveRegistrationDraftToken(nextToken);
  }

  await setActiveTab("responsible", true);
};

const handleTabChange = async (tab) => {
  if (tab === activeTab.value) return;

  if (tab === "responsible") {
    await goToResponsible();

    return;
  }

  await setActiveTab(tab, true);
};

const onAvatarChange = (file) => {
  avatarFile.value = file;
};

const onOKClick = async () => {
  if (
    isStudentUnderage.value &&
    activeTab.value === "student"
  ) {
    await goToResponsible();

    return;
  }

  await executeSubmit(() =>
    createStudent(buildPayload()),
  );
};

const saveRegistrationDraftToken = (token) => {
  registrationDraftToken.value = token;

  localStorage.setItem(
    REGISTRATION_DRAFT_TOKEN_STORAGE_KEY,
    token,
  );
};

const setActiveTab = async (
  tab,
  resetScroll = false,
) => {
  activeTab.value = tab;

  await nextTick();

  if (resetScroll) {
    scrollAreaRef.value?.setScrollPosition(
      "vertical",
      0,
      0,
    );
  }
};

watch(selectedState, (state) => {
  form.value.state_id = state?.value ?? null;
});

watch(selectedCity, (city) => {
  form.value.city_id = city?.value ?? null;
});

watch(responsibleSelectedState, (state) => {
  responsibleForm.value.state_id =
    state?.value ?? null;
});

watch(responsibleSelectedCity, (city) => {
  responsibleForm.value.city_id =
    city?.value ?? null;
});

watch(isStudentUnderage, (underage) => {
  if (
    !underage &&
    activeTab.value === "responsible"
  ) {
    activeTab.value = "student";
  }
});

watch(validationErrors, (errors) => {
  const fields = Object.keys(errors);

  if (
    fields.some(
      (field) => !field.startsWith("responsible"),
    )
  ) {
    activeTab.value = "student";

    return;
  }

  if (
    fields.some((field) =>
      field.startsWith("responsible"),
    )
  ) {
    activeTab.value = "responsible";
  }
});
</script>
