<template>
  <q-dialog ref="dialogRef" @hide="onDialogHide">
    <div style="width: 100%; max-width: 1100px">
      <q-card
        style="
          height: 560px;
          display: flex;
          flex-direction: column;
          overflow: hidden;
        "
      >
        <DefaultDialogHeader
          :title="card ? 'Editar Atividade' : 'Adicionar Atividade'"
          @close="onDialogCancel"
        />

        <DefaultForm
          ref="formRef"
          style="
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
          "
          @submit="onOKClick"
          @validation-error="handleValidationError"
        >
          <q-scroll-area ref="scrollAreaRef" class="form-dialog-scroll-area">
            <q-card-section class="row q-col-gutter-md q-pt-none">
              <CustomTabComponent
                v-if="card?.id"
                v-model:active-tab="currentTab"
                class="col-12 q-mb-md"
                :tabs="tabs"
              />

              <div
                v-show="currentTab === 'atividade'"
                class="col-12"
              >
                <div class="row q-col-gutter-md">
                  <DefaultInput
                    v-model="form.title"
                    v-model:error="validationErrors.title"
                    class="col-12"
                    label="Título da Tarefa"
                    :error-message="validationErrors.title"
                    :rules="[inputRules.required, maxLengthRule(255)]"
                  />

                  <DefaultSelect
                    v-model="form.scope"
                    v-model:error="validationErrors.scope"
                    class="col-12 col-sm-6"
                    emit-value
                    label="Destino"
                    map-options
                    :error-message="validationErrors.scope"
                    :options="scopeOptions"
                    :rules="[inputRules.required]"
                  />

                  <DefaultInputDatePicker
                    v-model="form.due_date_display"
                    v-model:untreated-date="form.due_date"
                    v-model:error="validationErrors.due_date"
                    class="col-12 col-sm-6"
                    label="Prazo de Entrega"
                    :error-message="validationErrors.due_date"
                    :rules="[dateRule]"
                  />

                  <UnitSelect
                    v-if="form.scope === 'specific'"
                    v-model="selectedUnit"
                    v-model:error="validationErrors.target_unit_id"
                    class="col-12 col-sm-6"
                    :error-message="validationErrors.target_unit_id"
                  />

                  <DefaultSelect
                    v-model="form.priority"
                    v-model:error="validationErrors.priority"
                    class="col-12 col-sm-6"
                    emit-value
                    label="Prioridade"
                    map-options
                    :error-message="validationErrors.priority"
                    :options="priorityOptions"
                    :rules="[inputRules.required]"
                  />

                  <DefaultSelect
                    v-model="form.phase"
                    v-model:error="validationErrors.phase"
                    class="col-12 col-sm-6"
                    emit-value
                    label="Fase"
                    map-options
                    :error-message="validationErrors.phase"
                    :options="phaseOptions"
                    :rules="[inputRules.required]"
                  />

                  <DefaultInput
                    v-model="form.sector"
                    v-model:error="validationErrors.sector"
                    class="col-12 col-sm-6"
                    label="Setor"
                    :error-message="validationErrors.sector"
                    :rules="[maxLengthRule(255)]"
                  />

                  <DefaultInput
                    v-model="form.description"
                    v-model:error="validationErrors.description"
                    class="col-12"
                    label="Descrição"
                    type="textarea"
                    :error-message="validationErrors.description"
                  />
                </div>
              </div>

              <div
                v-show="currentTab === 'comentarios'"
                class="col-12"
              >
                <div class="flex justify-end q-mb-sm">
                  <q-btn
                    v-if="canAdd"
                    color="primary"
                    icon="mdi-plus"
                    style="width: 40px; height: 40px"
                    unelevated
                    @click="onAddComment"
                  />
                </div>

                <div
                  style="
                    display: flex;
                    flex-direction: column;
                    gap: 8px;
                  "
                >
                  <template v-if="replies.length">
                    <KanbanCommentCard
                      v-for="reply in replies"
                      :key="reply.id"
                      :can-delete="canDelete"
                      :can-edit="canEdit"
                      :created-at="reply.created_at"
                      :reply="reply.reply"
                      :user-name="reply.user_name"
                      @delete="onDeleteComment(reply)"
                      @edit="onEditComment(reply)"
                    />
                  </template>

                  <div
                    v-else
                    class="flex flex-center full-height text-grey-5 text-body2"
                  >
                    Nenhum comentário registrado.
                  </div>
                </div>
              </div>

              <div
                v-show="currentTab === 'midias'"
                class="col-12"
              >
                <div class="flex justify-end q-mb-sm">
                  <q-btn
                    v-if="canAdd"
                    color="primary"
                    icon="mdi-upload-outline"
                    style="width: 40px; height: 40px"
                    unelevated
                    :loading="uploadingMedia"
                    @click="triggerFileInput"
                  />

                  <input
                    ref="fileInputRef"
                    style="display: none"
                    type="file"
                    @change="onFileSelected"
                  />
                </div>

                <div
                  style="
                    display: flex;
                    flex-direction: column;
                    gap: 8px;
                  "
                >
                  <template v-if="medias.length">
                    <KanbanMediaCard
                      v-for="media in medias"
                      :key="media.id"
                      :can-delete="canDelete"
                      :created-at="media.created_at"
                      :file-name="media.file_name"
                      :file-url="media.file_url"
                      :mime-type="media.mime_type"
                      :user-name="media.user_name"
                      @delete="onDeleteMedia(media)"
                    />
                  </template>

                  <div
                    v-else
                    class="flex flex-center full-height text-grey-5 text-body2"
                  >
                    Nenhuma mídia anexada.
                  </div>
                </div>
              </div>
            </q-card-section>
          </q-scroll-area>

          <q-separator />

          <q-card-actions
            align="right"
            class="q-pa-md q-gutter-sm"
            style="flex-shrink: 0"
          >
            <q-btn
              color="negative"
              label="Cancelar"
              no-caps
              outline
              @click="onDialogCancel"
            />

            <q-btn
              v-if="card?.id ? canEdit : canAdd"
              color="primary"
              label="Salvar"
              no-caps
              type="submit"
              unelevated
              :loading="loading"
            />
          </q-card-actions>
        </DefaultForm>
      </q-card>
    </div>
  </q-dialog>
</template>

<script setup>
import {
  createKanban,
  updateKanban,
} from "src/api/kanban";

import {
  createKanbanReply,
  deleteKanbanReply,
  getKanbanReplies,
  updateKanbanReply,
} from "src/api/kanban_reply";

import {
  deleteKanbanMedia,
  getKanbanMedias,
  uploadKanbanMedia,
} from "src/api/kanban_media";

import { computed, nextTick, onMounted, ref, watch } from "vue";
import { permissionStore } from "src/stores/permission";

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 CustomTabComponent from "src/components/shared/CustomTabComponent.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 KanbanCommentCard from "./KanbanCommentCard.vue";
import KanbanMediaCard from "./KanbanMediaCard.vue";
import UnitSelect from "src/components/selects/UnitSelect.vue";

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

const { card, initialPhase } = defineProps({
  card: {
    default: null,
    type: Object,
  },
  initialPhase: {
    default: "a_fazer",
    type: String,
  },
});

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

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

const permissions = permissionStore();

const fileInputRef = ref(null);
const formRef = ref(null);
const scrollAreaRef = ref(null);

const formatDisplayDate = (rawDate) => {
  if (!rawDate) return null;

  const [year, month, day] = rawDate.split("-");

  return `${day}/${month}/${year}`;
};

const { form, getUpdatedFields } = useForm(
  {
    description: card?.description ?? null,
    due_date: card?.due_date ?? null,
    due_date_display: formatDisplayDate(card?.due_date),
    phase: card?.phase ?? initialPhase,
    priority: card?.priority ?? "normal",
    responsible_user_id: card?.responsible_user_id ?? null,
    scope: card?.scope ?? "internal",
    sector: card?.sector ?? null,
    target_unit_id: card?.target_unit_id ?? null,
    title: card?.title ?? null,
  },
  { containerRef: scrollAreaRef },
);

const scrollToActivityComponent = async (
  component,
  containerRef,
  options,
) => {
  currentTab.value = "atividade";

  await nextTick();

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

const {
  loading,
  validationErrors,
  execute,
} = useSubmitHandler({
  containerRef: scrollAreaRef,
  formRef,
  onSuccess: () => onDialogOK(true),
  scrollFn: scrollToActivityComponent,
});

const selectedUnit = ref(
  card?.target_unit_id
    ? {
        value: card.target_unit_id,
      }
    : null,
);

const currentTab = ref("atividade");
const medias = ref([]);
const replies = ref([]);
const uploadingMedia = ref(false);

const tabs = computed(() => [
  {
    label: "Atividade",
    name: "atividade",
  },
  {
    label: "Comentários",
    name: "comentarios",
  },
  {
    label: "Mídias",
    name: "midias",
  },
]);

const canAdd = permissions.getAccess("franchisor_activities", "add");
const canDelete = permissions.getAccess("franchisor_activities", "delete");
const canEdit = permissions.getAccess("franchisor_activities", "edit");

const phaseOptions = [
  { label: "A Fazer", value: "a_fazer" },
  { label: "Em Progresso", value: "em_progresso" },
  { label: "Em Revisão", value: "em_revisao" },
  { label: "Concluído", value: "concluido" },
  { label: "Demandas Especiais", value: "demandas_especiais" },
];

const priorityOptions = [
  { label: "Alta", value: "alta" },
  { label: "Normal", value: "normal" },
  { label: "Baixa", value: "baixa" },
];

const scopeOptions = [
  { label: "Interno", value: "internal" },
  { label: "Todas as Unidades", value: "all" },
  { label: "Unidade Específica", value: "specific" },
];

const buildPayload = () => ({
  description: form.description || null,
  due_date: form.due_date || null,
  phase: form.phase,
  priority: form.priority,
  responsible_user_id: form.responsible_user_id,
  scope: form.scope,
  sector: form.sector || null,
  target_unit_id: form.scope === "specific" ? form.target_unit_id : null,
  title: form.title,
});

const dateRule = (value) => {
  if (!value) return true;

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

  if (!match) return "Informe uma data válida";

  const [, year, month, day] = match.map(Number);
  const date = new Date(year, month - 1, day);

  return (
    (date.getFullYear() === year &&
      date.getMonth() === month - 1 &&
      date.getDate() === day) ||
    "Informe uma data válida"
  );
};

const handleValidationError = async (component) => {
  currentTab.value = "atividade";

  await nextTick();

  if (component) {
    component.focus?.();
    scrollToComponent(component, scrollAreaRef);
  }
};

const loadMedias = async () => {
  if (!card?.id) return;

  medias.value = await getKanbanMedias(card.id);
};

const loadReplies = async () => {
  if (!card?.id) return;

  replies.value = await getKanbanReplies(card.id);
};

const maxLengthRule = (maximum) => (value) =>
  !value ||
  String(value).length <= maximum ||
  `O campo deve ter no máximo ${maximum} caracteres`;

const onAddComment = () => {
  $q.dialog({
    cancel: {
      color: "primary",
      label: "Cancelar",
      outline: true,
    },
    ok: {
      color: "primary",
      label: "Salvar",
    },
    prompt: {
      label: "Comentário *",
      model: "",
      type: "textarea",
    },
    title: "Adicionar Comentário",
  }).onOk(async (text) => {
    if (!text?.trim()) return;

    await createKanbanReply(card.id, {
      reply: text.trim(),
    });

    loadReplies();
  });
};

const onDeleteComment = (reply) => {
  $q.dialog({
    cancel: {
      color: "primary",
      label: "Cancelar",
      outline: true,
    },
    message: "Tem certeza que deseja excluir este comentário?",
    ok: {
      color: "negative",
      label: "Excluir",
    },
    title: "Excluir Comentário",
  }).onOk(async () => {
    await deleteKanbanReply(card.id, reply.id);

    loadReplies();
  });
};

const onDeleteMedia = (media) => {
  $q.dialog({
    cancel: {
      color: "primary",
      label: "Cancelar",
      outline: true,
    },
    message: `Deseja excluir "${media.file_name}"?`,
    ok: {
      color: "negative",
      label: "Excluir",
    },
    title: "Excluir Mídia",
  }).onOk(async () => {
    await deleteKanbanMedia(card.id, media.id);

    loadMedias();
  });
};

const onEditComment = (reply) => {
  $q.dialog({
    cancel: {
      color: "primary",
      label: "Cancelar",
      outline: true,
    },
    ok: {
      color: "primary",
      label: "Salvar",
    },
    prompt: {
      label: "Comentário",
      model: reply.reply,
      type: "textarea",
    },
    title: "Editar Comentário",
  }).onOk(async (text) => {
    if (!text?.trim()) return;

    await updateKanbanReply(card.id, reply.id, {
      reply: text.trim(),
    });

    loadReplies();
  });
};

const onFileSelected = async (event) => {
  const file = event.target.files?.[0];

  if (!file) return;

  uploadingMedia.value = true;

  try {
    await uploadKanbanMedia(card.id, file);
    await loadMedias();
  } finally {
    event.target.value = "";
    uploadingMedia.value = false;
  }
};

const triggerFileInput = () => {
  fileInputRef.value?.click();
};

const onOKClick = async () => {
  await execute(() => {
    if (card?.id) {
      const payload = {
        ...getUpdatedFields.value,
      };

      delete payload.due_date_display;

      return updateKanban(card.id, payload);
    }

    return createKanban(buildPayload());
  });
};

watch(selectedUnit, (unit) => {
  form.target_unit_id = unit?.value ?? null;
});

watch(
  () => form.scope,
  (scope) => {
    if (scope !== "specific") {
      selectedUnit.value = null;
      form.target_unit_id = null;
    }
  },
);

onMounted(() => {
  loadMedias();
  loadReplies();
});
</script>