<template>
  <div class="field is-grouped">
    <div
      class="control"
      id="ignore"
    >
      <label class="file-label">
        <input
          class="file-input"
          type="file"
          id="divfile"
          name="resume"
          @change="inputFile"
        />
        <span class="file-cta px-2 has-background-primary">
          <span class="icon-text is-clickable">
            <SvgIcon v-bind="{ name: 'attach-file.svg', type: 'white', size: 22 }"></SvgIcon>
            <span class="has-text-white">Chọn file</span>
          </span>
        </span>
      </label>
    </div>
    <div class="control">
      <a
        class="button is-primary"
        @click="download()"
      >
        Tải template
      </a>
      <a
        class="button is-light ml-6"
        v-if="datafile"
        @click="exportExcel()"
        >Xuất Excel</a
      >
    </div>
  </div>
  <div
    class="columns mb-0"
    v-if="msgInfo.length > 0"
  >
    <div class="column is-7 mb-0">
      <div class="notification is-white py-2 mb-2">
        <button
          class="delete"
          @click="msgInfo = []"
        ></button>
        <div style="max-height: 250px; overflow-y: auto">
          <article
            class="media py-0 my-0"
            v-for="(ele, key) in msgInfo"
            :key="key"
          >
            <figure class="media-left">
              <i :class="classinfo.find((v) => v.type === ele.type).icon_class"> </i>
            </figure>
            <div class="media-content">
              <div class="content">
                <p :class="classinfo.find((v) => v.type == ele.type).text_class">
                  {{ ele.message }}
                </p>
              </div>
            </div>
          </article>
        </div>
      </div>
      <p v-if="result">
        <span class="has-text-primary fsb-18"
          >{{ `Thành công: ${result.success_count || 0}` }} / {{ total || "" }}</span
        >
        <span class="has-text-danger fsb-18 ml-5">{{ `Lỗi: ${result.error_count || 0}` }} / {{ total || "" }}</span>
      </p>
    </div>
    <div
      class="column has-text-centered mb-0"
      v-if="ready"
    >
      <a
        :class="`button is-primary ${isloading ? 'is-loading' : ''}`"
        @click="insert()"
        v-if="countNew > 0"
        >Thêm mới ({{ countNew }}/{{ total }})</a
      >
      <a
        :class="`button is-dark ${isloading ? 'is-loading' : ''} ml-2`"
        @click="update()"
        v-if="countUdt > 0"
        >Cập nhật ({{ countUdt }}/{{ total }})</a
      >
    </div>
  </div>
  <DataTable
    v-bind="{ pagename: pagename }"
    v-if="pagedata"
  />
</template>

<script>
export default {
  props: ["code"],
  data() {
    return {
      classinfo: [
        {
          type: "success",
          icon_class: "mdi mdi-check",
          text_class: "has-text-primary",
        },
        {
          type: "error",
          icon_class: "mdi mdi-close has-text-danger",
          text_class: "has-text-danger",
        },
        {
          type: "warning",
          icon_class: "mdi mdi-alert has-text-warning",
          text_class: "has-text-warning",
        },
        {
          type: "waiting",
          icon_class: "mdi mdi-timer-sand has-text-primary",
          text_class: "has-text-primary",
        },
      ],
      msgInfo: [],
      isloading: false,
      datafile: undefined,
      requireFields: [],
      pagename: "importdata",
      file: undefined,
      ready: false,
      data: [],
      setting: undefined,
      countUdt: undefined,
      countNew: undefined,
      total: undefined,
      fileInfo: undefined,
      fileLog: undefined,
      result: undefined,
    };
  },
  async created() {
    this.setting = await this.$getdata("importsetting", { code: this.code }, undefined, true);
    this.requireFields = this.setting.detail;
  },
  beforeUnmount() {
    this.pagedata = undefined;
  },
  computed: {
    pagedata: {
      get: function () {
        return this.$store[this.pagename];
      },
      set: function (val) {
        this.$store.commit(this.pagename, val);
      },
    },
  },
  methods: {
    download() {
      window.open(`${this.$getpath()}static/excelform/${this.setting.template}`, "_blank");
    },
    async inputFile(v) {
      this.isloading = true;
      this.msgInfo = [];
      let fileList = document.getElementById("divfile").files;
      let files = Array.from(fileList);
      if (files.length === 0) return;
      var thefile = this.$upload(files[0], "file", 1);
      if (thefile.error) {
        this.$buefy.toast.open({ message: thefile.text, type: "is-danger" });
        return (this.isloading = false);
      }
      if (!(thefile.name.search(".xls") > 0 || thefile.name.search(".xlsx") > 0)) {
        let text = this.$find(
          this.$store.syspara,
          { category: "inform", classify: "import", code: "file-type-invalid" },
          "value",
        );
        this.msgInfo.push({ message: text, type: "error" });
        return (this.isloading = false);
      }
      let result = await this.$insertapi("upload", thefile.form, undefined, false);
      if (result === "error") {
        let text = this.$find(
          this.$store.syspara,
          { category: "inform", classify: "import", code: "file-upload-fail" },
          "value",
        );
        this.msgInfo.push({ message: text, type: "error" });
      } else {
        this.fileLog = result;
        this.fileInfo = thefile;
        this.fillData();
      }
      this.isloading = false;

      // Clear file
      document.getElementById("divfile").value = "";
    },
    async fillData() {
      let found = this.$findapi("readexcel");
      found.params = { name: this.fileInfo.filename };
      let result = await this.$getapi([found]);
      this.datafile = JSON.parse(result[0].data);
      let fields = [];
      this.datafile.schema.fields.forEach((ele) => {
        let field = this.$createField(ele.name, ele.name, "string", true);
        if (field.name !== "index") fields.push(field);
      });
      let copy = this.pagedata ? this.$copy(this.pagedata) : this.$getpage();
      let data = this.datafile.data;
      data.map((v) => (v.updater = this.$store.login.id));
      copy.update = { fields: fields, data: data };
      copy.data = data;
      copy.fields = fields;
      this.pagedata = copy;
      this.checkRequireFields(fields);
    },
    checkRequireFields(fields) {
      let misslist = [];
      Object.keys(this.requireFields).map((v) => {
        let found = fields.find((x) => x.name === v);
        if (!found) misslist.push(v);
      });
      if (misslist.length > 0) {
        let text = `Thiếu các cột bắt buộc: ${misslist.join(", ")}`;
        this.msgInfo.push({ message: text, type: "error" });
      } else {
        this.validateFontend();
      }
    },
    validateFontend() {
      let self = this;
      var checkValid = function (name, obj, data) {
        var error = false;
        if (obj.empty === "no" || !self.$empty(obj.api)) {
          data.map((x) => {
            if (self.$empty(x[name])) {
              x["error"] = `${name} không được bỏ trống`;
              error = true;
            }
          });
        }
        if (!error && obj.type === "number") {
          data.map((x) => {
            if (self.$empty(x[name])) x[name] = null;
            else {
              if (self.$isNumber(x[name])) x[name] = self.$formatNumber(x[name]);
              else {
                x["error"] = `${name} không phải là số`;
                error = true;
              }
            }
          });
        }
        if (!error && obj.type === "date") {
          data.map((x) => {
            if (self.$empty(x[name])) x[name] = null;
            else {
              if (self.$dayjs(x[name], "YYYY/MM/DD").isValid()) x[name] = self.$dayjs(x[name]).format("YYYY-MM-DD");
              else {
                x["error"] = `${name} không phải ngày hợp lệ`;
                error = true;
              }
            }
          });
        }
        if (!error && obj.type === "string") {
          data.map((x) => (x[name] = self.$empty(x[name]) ? null : x[name]));
        }
        return [error, data];
      };
      let err = false;
      let data = this.$copy(this.pagedata.data);
      Object.keys(this.requireFields).map((v) => {
        let obj = this.requireFields[v];
        let result = checkValid(v, obj, data);
        data = result[1];
        if (result[0] === true) err = true;
      });
      if (err) this.showError(data);
      else {
        if (data.length > 5000) {
          this.msgInfo.push({
            message: `Tổng số bản ghi là ${data.length}. Chỉ hiển thị 5000 trong bảng dữ liệu`,
            type: "warning",
          });
        } else {
          this.msgInfo.push({
            message: `Tổng số bản ghi là ${data.length}`,
            type: "success",
          });
        }
        let copy = this.$copy(this.pagedata);
        copy.update = { data: data.length > 5000 ? data.slice(0, 5000) : data };
        this.pagedata = copy;
        this.data = data;
        this.findKey(data);
      }
    },
    showError(data) {
      data = data.filter((v) => v.error);
      this.msgInfo.push({
        message: "Dữ liệu có lỗi. Hãy kiểm tra lại",
        type: "error",
      });
      let field = this.$createField("error", "error", "string", true, true);
      field.color = "red";
      let fields = this.$copy(this.pagedata.fields);
      fields = [field].concat(fields);
      let copy = this.$clone(this.pagedata);
      copy.data = data;
      copy.fields = fields;
      copy.update = { data: data, fields: fields };
      this.pagedata = copy;
    },

    // ✅ METHOD CHÍNH: TÌM KEY VÀ KIỂM TRA UPDATE PERMISSION
    async findKey(rows) {
      this.msgInfo.push({
        message: "Bắt đầu kiểm tra dữ liệu",
        type: "waiting",
      });

      let keys = [];
      let related = [];

      // 1. Tạo dữ liệu gửi lên: Dùng chính tên cột Excel để chứa giá trị
      let mappedRows = rows.map((row) => {
        let newRow = { ...row };
        for (const [excelColName, config] of Object.entries(this.requireFields)) {
          if (excelColName in row) {
            newRow[excelColName] = row[excelColName];
          }
        }
        return newRow;
      });

      // 2. Cấu hình Mapping cho Backend
      for (const [excelColName, value] of Object.entries(this.requireFields)) {
        if (value.key === "yes") {
          keys.push({
            key: excelColName,
            value: value,
          });
        }
        // Nếu là trường Lookup
        if (value.api) {
          related.push({
            key: excelColName,
            value: value,
          });
        }
      }

      let conn = this.$findapi(this.setting.api);
      let payload = {
        name: conn.url.replace("data/", "").replace(/\//g, ""),
        data: mappedRows,
        keys: keys,
        related: related,
      };

      try {
        let rs = await this.$insertapi("findkey", payload);
        if (rs && rs.data) {
          this.data = rs.data;
          this.total = this.data.length;

          // ✅ KIỂM TRA CẤU HÌNH UPDATE
          this.checkUpdatePermission();

          // 1. Lọc ra danh sách các lỗi
          let errors = this.data
            .map((v, i) => (v.error ? { line: i + 1, msg: v.error } : null))
            .filter((v) => v !== null);

          this.countNew = this.data.filter((v) => !v.id && !v.error).length;
          this.countUdt = this.data.filter((v) => v.id && !v.error).length;
          this.ready = true;

          // 2. Nếu có lỗi, hiển thị chi tiết từng dòng vào msgInfo
          if (errors.length > 0) {
            errors.forEach((err) => {
              this.msgInfo.push({
                message: `Dòng ${err.line}: ${err.msg}`,
                type: "error",
              });
            });

            this.msgInfo.push({
              message: `Phát hiện tổng cộng ${errors.length} lỗi. Vui lòng sửa file và upload lại.`,
              type: "warning",
            });
          } else {
            this.msgInfo.push({
              message: `Kiểm tra hoàn tất: Toàn bộ ${this.total} dòng dữ liệu hợp lệ.`,
              type: "success",
            });
          }

          this.showStatus();
        }
      } catch (e) {
        this.isloading = false;
        this.msgInfo.push({
          message: "Lỗi hệ thống khi kiểm tra",
          type: "error",
        });
      }
    },

    checkUpdatePermission() {
      // Tìm các trường key có update = "no"
      let noUpdateFields = [];

      Object.entries(this.requireFields).forEach(([excelColName, config]) => {
        // Nếu là trường key và update = "no"
        // Mặc định nếu không khai báo update thì coi như "yes"
        if (config.key === "yes" && config.update === "no") {
          noUpdateFields.push({
            name: excelColName,
            field: config.field || excelColName,
          });
        }
      });

      // Nếu không có trường nào cấm update thì bỏ qua
      if (noUpdateFields.length === 0) {
        return;
      }

      // Kiểm tra từng bản ghi
      this.data.forEach((row, index) => {
        // Nếu bản ghi đã tồn tại (có id) và chưa có lỗi
        if (row.id && !row.error) {
          // Lấy danh sách các trường key bị trùng
          let duplicatedFields = [];

          noUpdateFields.forEach((field) => {
            // Kiểm tra xem trường này có giá trị không
            if (row[field.name]) {
              duplicatedFields.push(field.name);
            }
          });

          // Nếu có trường nào bị trùng, đánh dấu lỗi
          if (duplicatedFields.length > 0) {
            row.error = `Bản ghi đã tồn tại với ${duplicatedFields.join(", ")}. Không được phép cập nhật.`;
          }
        }
      });
    },

    showStatus() {
      let field = this.$createField("record_status", "Status", "string", true, true);
      field.color = "blue";
      let fields = this.$copy(this.pagedata.fields);
      fields.push(field);
      this.$store.commit("updateState", {
        name: this.pagename,
        key: "fields",
        data: fields,
      });
      let data = this.$copy(this.pagedata.data);
      data.map((v, i) => (v.record_status = this.data[i].id ? "Tồn tại" : "Mới"));
      this.$store.commit("updateState", {
        name: this.pagename,
        key: "data",
        data: data,
      });
      let copy = this.$clone(this.pagedata);
      this.pagedata = undefined;
      setTimeout(() => (this.pagedata = copy), 10);
    },

    //Helper: Xóa trường lookup (giữ lại id của mapping)
    cleanupLookupFields(data) {
      return data.map((row) => {
        let newRow = {};

        Object.entries(this.requireFields).forEach(([excelColName, config]) => {
          let dbFieldName = config.field || config.field;
          if (dbFieldName && row[excelColName] !== undefined) {
            newRow[dbFieldName] = row[excelColName];
          }
        });

        Object.keys(row).forEach((key) => {
          if (key !== "index" && !this.requireFields[key]) {
            newRow[key] = row[key];
          }
        });

        return newRow;
      });
    },

    async insert() {
      this.isloading = true;
      this.result = undefined;
      let conn = this.$findapi(this.setting.api);
      let obj = {
        code: this.$id(),
        model: conn.url.replace("data/", "").replace("/", ""),
        file: this.fileInfo.name,
        fields: this.setting.detail,
      };
      await this.$insertapi("importlog", obj);
      var interval = setInterval(() => this.getResult(obj.code), 2000);

      //Lọc bản ghi KHÔNG có id (bản ghi mới)
      let filter = this.data.filter((v) => !v.id && !v.error);

      //Xóa trường lookup trước khi gửi
      filter = this.cleanupLookupFields(filter);
      filter = filter.map((v) => this.$resetNull(v));
      this.total = filter.length;

      //Gửi lên API - Backend sẽ INSERT
      let result;
      if (this.setting.call_api) {
        result = await this.$insertapi(
          this.setting.call_api,
          { data: filter, user: this.$store.login.id },
          undefined,
          obj.code,
        );
      } else {
        result = await this.$insertapi(this.setting.api, filter, undefined, obj.code);
      }
      this.isloading = false;
      clearInterval(interval);
      this.getResult(obj.code);

      // Xử lý result/response mới
      if (result === "error") {
        this.msgInfo.push({
          message: "Có lỗi hệ thống khi thực hiện",
          type: "error",
        });
        return;
      }

      let hasError = false;
      let errorMessages = [];

      // Kiểm tra entries có lỗi không
      if (result.entries && Array.isArray(result.entries)) {
        result.entries.forEach((entry) => {
          if (entry.error) {
            hasError = true;
            errorMessages.push(entry.error);
          }
        });
      }

      // Nếu có message chứa từ khóa lỗi (dự phòng)
      if (
        result.message &&
        (result.message.toLowerCase().includes("lỗi") || result.message.toLowerCase().includes("không tồn tại"))
      ) {
        hasError = true;
        errorMessages.push(result.message);
      }

      if (hasError) {
        // Hiển thị lỗi chi tiết
        errorMessages.forEach((msg) => {
          this.msgInfo.push({ message: msg, type: "error" });
        });
        this.msgInfo.push({
          message: "Có lỗi trong quá trình xử lý. Vui lòng kiểm tra và thử lại.",
          type: "warning",
        });
      } else {
        // Thành công thật sự
        const successMsg = this.countNew
          ? `Thêm mới thành công: ${this.countNew} bản ghi`
          : `Cập nhật thành công: ${this.countUdt} bản ghi`;

        this.msgInfo.push({ message: successMsg, type: "success" });
        this.msgInfo.push({
          message: result.message || "Hoàn tất.",
          type: "success",
        });

        // Chỉ emit close khi KHÔNG có lỗi
        setTimeout(() => {
          this.$emit("close");
        }, 1500);
      }

      // Luôn cập nhật count về undefined để nút biến mất
      this.countNew = undefined;
      this.countUdt = undefined;
    },

    async update() {
      this.isloading = true;
      this.result = undefined;
      let conn = this.$findapi(this.setting.api);
      let obj = {
        code: this.$id(),
        model: conn.url.replace("data/", "").replace("/", ""),
        file: this.fileInfo.name,
        fields: this.setting.detail,
      };
      await this.$insertapi("importlog", obj);
      var interval = setInterval(() => this.getResult(obj.code), 2000);

      //Lọc bản ghi CÓ id (bản ghi tồn tại) VÀ KHÔNG CÓ LỖI
      let filter = this.data.filter((v) => v.id && !v.error);

      //Xóa trường lookup trước khi gửi
      filter = this.cleanupLookupFields(filter);
      filter = filter.map((v) => this.$resetNull(v));
      this.total = filter.length;

      //Gửi lên API - Backend sẽ UPDATE
      let result = await this.$insertapi(this.setting.call_api || this.setting.api, filter, undefined, obj.code);
      this.isloading = false;
      clearInterval(interval);
      this.getResult(obj.code);

      if (result === "error") {
        return this.msgInfo.push({ message: "Có lỗi xảy ra", type: "error" });
      }

      let hasError = false;
      let errorMessages = [];

      // Kiểm tra có lỗi trong result không
      if (Array.isArray(result)) {
        result.forEach((item) => {
          if (item.error) {
            hasError = true;
            errorMessages.push(item.error || JSON.stringify(item.note));
          }
        });
      }

      if (hasError) {
        errorMessages.forEach((msg) => {
          this.msgInfo.push({ message: msg, type: "error" });
        });
      } else {
        this.msgInfo.push({
          message: `Cập nhật thành công: ${this.countUdt} bản ghi`,
          type: "success",
        });
        this.countUdt = undefined;
        this.$emit("modalevent", { name: "reload" });
      }
    },

    async getResult(logcode) {
      let found = this.$findapi("importlog");
      found.params.filter = { code: logcode };
      let rs = await this.$getapi([found]);
      this.result = rs[0].data.rows[0];
    },

    exportExcel() {
      let dataType = {};
      this.pagedata.fields.map((v) => (dataType[v.label.indexOf(">") >= 0 ? v.name : v.label] = "String"));
      let data = this.pagedata.dataFilter || this.pagedata.data;
      this.$exportExcel(
        data,
        "data-export",
        this.pagedata.fields.map((v) => v.name),
        dataType,
      );
    },
  },
};
</script>
