<template>
  <div class="accordion" id="accordionExample">
    <div
      class="card rounded-0 mb-2"
      v-for="(innerGroupItem, j) in propertyBuilderForm"
      :key="j"
    >
      <!-- v-if="innerGroupItem.key != 'organhMeta'" -->
      <div
        class="card-header p-3"
        :id="'heading' + j"
        type="button"
        data-bs-toggle="collapse"
        :data-bs-target="'#collapse' + j"
        aria-expanded="false"
        :aria-controls="'collapse' + j"
      >
        <div class="d-flex justify-content-between align-items-center">
          <p class="p-0 m-0">
            {{ innerGroupItem.title }}
          </p>
          <span class="tavasi tavasi-Component-358--1"></span>
        </div>
      </div>

      <div
        :id="'collapse' + j"
        class="collapse"
        :aria-labelledby="'heading' + j"
        data-parent="#accordionExample"
      >
        <div class="card-body">
          <form :key="render">
            <div class="container-fluid">
              <div class="row">
                <div
                  v-for="(formElement, index) in refactorItems(
                    innerGroupItem.items
                  )"
                  :class="formElement.colClass ?? 'col-12'"
                >
                  <component
                    :key="index"
                    :formElement="getValueToFormElement(formElement)"
                    :inputClass="formElement.inputClass"
                    :labelClass="formElement.labelClass"
                    :is="
                      returnComponentName(
                        innerGroupItem,
                        formElement.type,
                        formElement.key
                      )
                    "
                    @take-value="saveComponentValue($event, formElement)"
                    @keydown="saveKeydown($event)"
                    @openModalTags="openModalTags"
                    class="component inside-entity"
                  ></component>
                </div>
              </div>
            </div>

            <div
              v-if="
                isEditable(innerGroupItem?.key, innerGroupItem.submit_label)
              "
              class="d-flex justify-content-end"
            >
              <button
                type="submit"
                class="btn btn-primary mt-3 px-3"
                @click.prevent="saveProperty(innerGroupItem)"
              >
                <span>{{ innerGroupItem.submit_label ?? "ثبت" }}</span>
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import repoApi from "~/apis/repoApi";
import { mapState } from "pinia";
import { useCommonStore } from "~/stores/commonStore";

import SelectComponentDefault from "~/components/SelectComponentDefault.vue";
import SelectComponent from "~/components/SelectComponent.vue";
import InputComponent from "~/components/InputComponent.vue";
import LabelComponent from "~/components/LabelComponent.vue";
import tagsComponent from "~/components/tagsComponent.vue";
import DateComponent from "~/components/DateComponent.vue";
import TextareaComponent from "~/components/TextareaComponent.vue";
/**
 * @vue-data {Object} [listUpdatedText = {}] - متن‌های به‌روزشده در لیست.
 * @vue-data {undefined} [httpService = undefined] - سرویس HTTP برای درخواست‌ها.
 * @vue-computed {Object} [mapState.entity.selectedItemEntityGetter] - مورد انتخاب شده
 * @vue-computed {Object} [mapState.userPermisionGetter] - دریافت کننده مجوز کاربر
 * @vue-computed {Object} [mapState.currentUser] -  اطلاعات کاربر
 * @vue-event {Function} [mapMutations.SET_ITEM_ENTITY] -  تابع برای قرار دادن موجودیت‌های آیتم
 */
export default {
  // props: ["propertyBuilderForm"],
  props: {
    propertyBuilderForm: {
      default() {
        return [];
      },
      type: Array,
    },
    entityProp: {
      default() {
        return undefined;
      },
    },
    readOnly: {
      default: false,
    },
  },

  beforeMount() {
    this.httpService = useNuxtApp()["$http"];
  },
  mounted() {
    console.log("property builder");

    if (this.entityProp) {
      this.entity_source = this.entityProp;
      this.entity_id = this.entityProp._id ?? undefined;

      this.render++;
    } else this.getEntityBase();
  },
  watch: {
    activeTabGetter(newVal) {
      if (newVal.key == "meta") {
        this.getEntityBase();
      }
    },
  },
  data() {
    return {
      fetchingData: false,
      httpService: undefined,
      entity_source: undefined,
      entity_id: undefined,
      render: 1,
      selectedCard: null,
      listUpdatedText: {},
    };
  },
  computed: {
    ...mapState(useCommonStore, [
      // "selectedItemEntityGetter",
      "activeTabGetter",
    ]),
    ...mapState(useCommonStore, ["userPermisionGetter", "currentUser"]),
  },
  methods: {
    // ...mapMutations("entity", ["SET_ITEM_ENTITY"]),
    openModalTags(item) {
      this.$emit("editPropertyTags", item);
    },
    refactorItems(items) {
      let res = [];
      items.forEach((el) => {
        res.push(el);
      });
      return res;
    },

    toggleCard(j) {
      if (this.selectedCard === j) {
        this.selectedCard = null; // اگر کارت فعال است، غیرفعال شود
      } else {
        this.selectedCard = j; // اگر کارت فعال نیست، فعال شود
      }
    },
    getEntityBase() {
      let self = this;
      this.getEntityInfo().then(() => {
        // if (!self.entity) {
        //   self.entity = self.selectedItemEntityGetter;
        // }
        self.render++;
      });
    },
    /**
     * بررسی امکان ویرایش بر اساس کلید داده شده.
     * @param {String} key - کلیدی که نیاز به بررسی دارد.
     * @returns {Boolean} نتیجه بررسی امکان ویرایش.
     * @description این متد بر اساس کلید داده شده و بررسی سطح دسترسی، امکان ویرایش را تعیین می‌کند.
     * @example
     * const editable = this.isEditable("example_key"); // true or false
     */

    isEditable(key, label = "ثبت") {
      if (this.readOnly) return false;
      if (label == "") return false;
      let res = key ? false : true;
      if (key) {
        let key_root = this.$route.params.key;
        // console.log(key_root)
        res = this.hasPermission(key_root + "_property");

        if (!res) res = this.hasPermission(key + "_edit");
      }

      return res;
    },
    /**
     * بررسی سطح دسترسی کاربر برای یک مجوز خاص.
     * @param {String} permission - مجوزی که نیاز به بررسی دارد.
     * @returns {Boolean} نتیجه بررسی سطح دسترسی.
     * @description این متد سطح دسترسی کاربر فعلی را برای یک مجوز خاص بررسی می‌کند.
     * @example
     * const hasAccess = this.hasPermission("admin_edit"); // true or false
     */
    hasPermission(permission) {
      if (this.currentUser?.user_level > 1) return true;

      if (this.userPermisionGetter && this.userPermisionGetter.length)
        return this.userPermisionGetter.includes(permission);
      return false;
    },
    /**
     * بازگشت نام کامپوننت بر اساس نوع و امکان ویرایش.
     * @param {Object} innerGroupItem - آیتمی که نیاز به بررسی دارد.
     * @param {String} type - نوع ورودی (مثل textarea, select, date).
     * @returns {String} نام کامپوننت مناسب.
     * @description این متد بر اساس نوع ورودی و امکان ویرایش، نام کامپوننت مناسب را برمی‌گرداند.
     * @example
     * const componentName = this.returnComponentName({ key: "description" }, "textarea"); // "TextareaComponent"
     */
    returnComponentName(innerGroupItem, type, key) {
      if (!this.isEditable(innerGroupItem?.key)) return "LabelComponent";

      if (type == "textarea") return "TextareaComponent";
      else if (type == "select") return "SelectComponentDefault";
      else if (type == "date") return "DateComponent";
      else if (type == "tags") return "tagsComponent";
      else return "InputComponent";
    },
    // /**
    //  * تبدیل تاریخ به فرمت فارسی.
    //  * @param {Object} item - آیتمی که شامل تاریخ است.
    //  * @returns {String} تاریخ به فرمت فارسی.
    //  * @description این متد تاریخ موجود در آیتم را به فرمت فارسی تبدیل می‌کند.
    //  * @example
    //  * const persianDate = this.datefa({ begin_date: "2023-05-29T00:00:00Z" }); // "۱۴۰۲/۳/۸"
    //  */
    // // datefa(item) {
    //   var m = this.selectedItemEntityGetter.begin_date;
    //   var d = new Date(m).toLocaleDateString("fa-IR");
    //   return d;
    // },
    /**
     * دریافت مقادیر فرم برای عناصر فرم.
     * @param {Object} elements - عناصر فرم که نیاز به مقداردهی دارند.
     * @returns {Object} عناصر فرم با مقادیر تنظیم شده.
     * @description این متد مقادیر مناسب را به عناصر فرم اختصاص می‌دهد.
     * @example
     * const formElements = this.getValueToFormElement({ key: "name", value: "" });
     * // formElements.value برابر با مقدار موجود در entity است.
     */
    getValueToFormElement(elements) {
      let source = this.entity_source;

      Object.keys(elements).forEach((key, index) => {
        if (source) {
          let key = elements.key.replace("__", ".");
          let value = undefined;
          if (key.includes(".")) {
            let keys = key.split(".");
            let elemntKey = source;
            let kk = "";
            for (var i = 0; i < keys.length - 1; i++) {
              kk = keys[i];
              if (elemntKey[kk]) elemntKey = elemntKey[kk];
            }
            kk = keys[keys.length - 1];
            if (elemntKey[kk]) value = elemntKey[kk];
          } else {
            value = source[key];
          }
          elements["value"] = value;
        }
      });
      return elements;
    },
    /**
     * ذخیره مقدار کامپوننت به صورت موقت.
     * @param {any} value - مقدار جدید کامپوننت.
     * @param {Object} formElement - عنصر فرم که مقدار جدید برای آن تنظیم شده است.
     * @description این متد مقدار جدید کامپوننت را به صورت موقت در لیست به‌روزرسانی‌ها ذخیره می‌کند.
     * @example
     * this.saveComponentValue("new value", { key: "description" });
     */
    saveComponentValue(value, formElement) {
      //در صورت تغییر نگهداری می شود تا وقتی کلید ثبت زد، ذخیره شود
      if (this.entity_source && this.entity_source[formElement.key] != value) {
        this.listUpdatedText[formElement.key] = value;
      }
    },

    async getEntityInfo() {
      if (this.fetchingData) return;

      let key = this.$route.params.key;
      let entityId = this.$route.params.id ?? this.entity_id;
      if (key == "qasection" || key == "rgsection") key = "qaqanon";

      // console.log("qaqanon", entityId)
      //if (!(key == "qasection" || key == "rgsection") || !entityId) {
      if (!entityId) {
        return;
      }

      // "public/get/byid/{{index_key}}/{{entity_id}}"
      this.fetchingData = true;
      let url = repoUrl() + repoApi.public.get;

      url = url.replace("{{index_key}}", key);
      url = url.replace("{{entity_id}}", entityId);

      // console.log(url)
      let self = this;
      return await this.httpService
        .getRequest(url)
        .then((res) => {
          // console.log(res);

          self.entity_source = res._source;
          self.entity_id = res._id ?? undefined;
          this.fetchingData = false;
          this.$emit("entityUpdate", this.entity_source);
        })
        .finally(() => {
          this.fetchingData = false;
        });
    },
    /**
     * ذخیره تغییرات در سرور.
     * @description این متد تغییرات موقتی را به سرور ارسال و ذخیره می‌کند.
     * @example
     * this.saveProperty();
     */
    saveProperty(innerGroupItem) {
      // console.log("saveProperty");

      let id = this.$route.params.id ?? this.entity_id;
      let key = this.$route.params.key;

      if (!id) {
        console.log("not id in route params");
        return;
      }

      //  اگر تغییری نداشته باشیم، meta به صورت "{}" خواهد بود.
      if (JSON.stringify(this.listUpdatedText).length > 2) {
        if (this.fetchingData) return;
        this.fetchingData = true;

        let formData = {
          id: id,
          meta: JSON.stringify(this.listUpdatedText),
        };

        let url = "";
        if (key == "qasection" || key == "rgsection") {
          //در این حالت چون مخزن اصل قانون با اجزاء قانون متفاوت هست ، تغییرات در هر دو به نحو خاصی باید إعمال شود.
          url =
            this.repoMicroServiceName + repoApi.public.updateProperty_byRelated;
          url = url.replace("{{appname}}", this.buildName());
          url = url.replace("{{sub_key}}", key);
          key = "qaqanon";
        } else {
          url = repoUrl() + repoApi.public.updateEntity;
        }

        url = url.replace("{{index_key}}", key);
        url = url.replace("{{id}}", id);

        this.httpService.postRequest(url, formData).then((res) => {
          this.fetchingData = false;
          this.mySwalToast({
            html: res?.message ?? "با موفقیت ثبت شد.",
          });

          this.getEntityInfo();
        });
      } else {
        this.mySwalToast({
          html: "تغییری جهت ذخیره یافت نشد.",
          icon: "error",
        });
      }
    },

    /**
     * هندلر برای رویداد فشردن کلید.
     * @param {Event} event - رویداد فشردن کلید.
     * @description این متد به عنوان هندلر برای رویداد فشردن کلید استفاده می‌شود.
     * @example
     * // در قالب رویداد keydown در یک المنت
     * <input @keydown="saveKeydown" />
     */
    saveKeydown(event) {
      // console.log(event);
    },
  },
  components: {
    SelectComponentDefault,
    SelectComponent,
    InputComponent,
    LabelComponent,
    tagsComponent,
    DateComponent,
    TextareaComponent,
  },
};
</script>

<style lang="scss" scoped>
.card-header {
  div {
    span {
      transform: rotate(90deg);
      transition: transform 0.3s ease;
      color: #000;
    }
  }
}
.card {
  border-radius: 0.6em !important;
  border: none;
}

.card-header {
  border-bottom: none;
  border-radius: 0.6em !important;

  &[aria-expanded="true"] {
    border-bottom-left-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
    background-color: var(--header-color);

    div {
      p {
        color: #fff;
      }
      span {
        transform: rotate(-90deg) !important;
        transition: transform 0.3s ease;
        color: #fff;
      }
    }
  }
}
.btn-primary {
  color: #fff;
}
.show {
  border: 1px solid var(--header-color) !important;
  margin-bottom: 5px;
  border-radius: 0 0 0.6em 0.6em !important;
}
</style>
