<template>
  <div class="field is-grouped">
    <div class="file is-primary m-0">
      <label class="file-label">
        <input
          class="file-input"
          type="file"
          id="divfile"
          name="resume"
          @change="inputFile"
        />
        <span
          class="file-cta"
          style="padding-left: 0.5rem"
        >
          <span class="icon-text">
            <span class="icon">
              <Icon
                name="material-symbols:attach-file"
                :size="18"
              />
            </span>
            <span class="font-medium">Chọn file</span>
          </span>
        </span>
      </label>
    </div>
    <button
      class="button is-primary is-light"
      @click="download"
    >
      <span class="icon">
        <Icon
          name="material-symbols:download"
          :size="20"
        />
      </span>
      <span>Tải template</span>
    </button>
    <button
      v-if="datafile"
      class="button is-success is-light"
      @click="exportExcel"
    >
      <span class="icon">
        <Icon
          name="mdi:microsoft-excel"
          :size="20"
        />
      </span>
      <span>Xuất Excel</span>
    </button>
  </div>
  <div
    class="fixed-grid has-12-cols"
    v-if="msgInfo.length > 0"
  >
    <div class="grid">
      <div class="cell is-col-span-9">
        <div class="notification fs-14">
          <button
            class="delete"
            @click="msgInfo = []"
          ></button>
          <div
            class="content"
            style="max-height: 250px; overflow-y: auto"
          >
            <p
              v-for="(ele, i) in msgInfo"
              :key="i"
              class="mb-2"
            >
              <span class="icon-text">
                <span class="icon">
                  <Icon
                    :name="classinfo.find((v) => v.type === ele.type).icon"
                    :size="18"
                    :class="classinfo.find((v) => v.type === ele.type).color"
                  />
                </span>
                <span v-html="ele.message"></span>
              </span>
            </p>
          </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
        v-if="ready"
        class="cell is-col-span-3"
      >
        <div class="buttons">
          <button
            v-if="countNew > 0"
            :class="['button is-success', isloading && 'is-loading']"
            @click="insert"
          >
            Thêm mới ({{ countNew }}/{{ total }})
          </button>
          <button
            v-if="countUdt > 0"
            :class="['button is-primary is-light', isloading && 'is-loading']"
            @click="update"
          >
            Cập nhật ({{ countUdt }}/{{ total }})
          </button>
        </div>
      </div>
    </div>
  </div>
  <DataTable
    v-if="pagedata"
    :pagename="pagename"
  />
</template>

<script>
export default {
  props: ["code"],
  data() {
    return {
      classinfo: [
        {
          type: "success",
          icon: "material-symbols:check-rounded",
          color: "has-text-success",
        },
        {
          type: "error",
          icon: "material-symbols:cancel-rounded",
          color: "has-text-danger",
        },
        {
          type: "warning",
          icon: "material-symbols:warning-rounded",
          color: "has-text-warning",
        },
        {
          type: "waiting",
          icon: "material-symbols:hourglass-top-rounded",
          color: "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() {
      this.isloading = true;
      this.msgInfo = [];
      const files = document.getElementById("divfile").files;
      if (files.length === 0) return;

      const file = files.item(0);
      let thefile = this.$upload(file, "file", 1);

      if (thefile.error) {
        this.$snackbar(thefile.text, "Error");
        return (this.isloading = false);
      }
      if (!(thefile.name.search(".xls") > 0 || thefile.name.search(".xlsx") > 0)) {
        const message = this.$find(
          this.$store.syspara,
          { category: "inform", classify: "import", code: "file-type-invalid" },
          "value",
        );
        this.msgInfo.push({ message, type: "error" });
        return (this.isloading = false);
      }
      let result = await this.$insertapi("upload", thefile.form, undefined, false);
      if (result === "error") {
        const message = this.$find(
          this.$store.syspara,
          { category: "inform", classify: "import", code: "file-upload-fail" },
          "value",
        );
        this.msgInfo.push({ message, type: "error" });
      } else {
        this.fileLog = result;
        this.fileInfo = thefile;
        this.fillData();
      }
      this.isloading = false;

      // Clear file
      document.getElementById("divfile").value = "";
    },
    async fillData() {
      const readExcelApi = this.$findapi("readexcel");
      readExcelApi.params = { name: this.fileInfo.filename };
      const result = await this.$getapi([readExcelApi]);
      this.datafile = JSON.parse(result[0].data);
      const fields = [];

      this.datafile.schema.fields.forEach((ele) => {
        let field = this.$createField(ele.name, ele.name, "string", true);
        if (field.name !== "index") fields.push(field);
      });

      const copy = this.pagedata ? this.$copy(this.pagedata) : this.$getpage();
      const data = this.datafile.data;
      // data.map((v) => (v.updater = this.$store.login.id));
      data.map((v) => (v.updater = 1));
      copy.update = { fields, 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) {
        const message = `Thiếu các cột bắt buộc: ${misslist.join(", ")}`;
        this.msgInfo.push({ message, type: "error" });
      } else {
        this.validateFrontend();
      }
    },
    validateFrontend() {
      let self = this;
      const checkValid = function (name, obj, data) {
        let 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",
      });
      const field = this.$createField("error", "error", "string", true, true);
      field.color = "red";
      let fields = this.$copy(this.pagedata.fields);
      fields = [field].concat(fields);
      const copy = this.$clone(this.pagedata);
      copy.data = data;
      copy.fields = fields;
      copy.update = { data, 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",
      });

      const keys = [];
      const related = [];

      // 1. Tạo dữ liệu gửi lên: Dùng chính tên cột Excel để chứa giá trị
      const mappedRows = rows.map((row) => {
        const 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,
          });
        }
      }

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

      try {
        const rs = await this.$insertapi("findkey", payload, undefined, false);
        if (rs === "error") throw new Error();
        else {
          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
          const 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) {
        console.error(e);
        this.isloading = false;
        this.msgInfo.push({
          message: `Lỗi hệ thống khi kiểm tra: ${e.message}`,
          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() {
      const field = this.$createField("record_status", "Status", "string", true, true);
      field.color = "blue";
      const fields = this.$copy(this.pagedata.fields);
      fields.push(field);
      this.$store.commit("updateState", {
        name: this.pagename,
        key: "fields",
        data: fields,
      });
      const data = this.$copy(this.pagedata.data);
      data.forEach((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,
      });
      const 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;
      const conn = this.$findapi(this.setting.api);
      const importLogPayload = {
        code: this.$id(),
        model: conn.url.replace("data/", "").replace("/", ""),
        file: this.fileInfo.name,
        fields: this.setting.detail,
      };
      await this.$insertapi("importlog", importLogPayload);
      const interval = setInterval(() => this.getResult(importLogPayload.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,
          importLogPayload.code,
        );
      } else {
        result = await this.$insertapi(this.setting.api, filter, undefined, importLogPayload.code);
      }

      this.isloading = false;
      clearInterval(interval);
      this.getResult(importLogPayload.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;
      const 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;
      const conn = this.$findapi(this.setting.api);
      const importlogPayload = {
        code: this.$id(),
        model: conn.url.replace("data/", "").replace("/", ""),
        file: this.fileInfo.name,
        fields: this.setting.detail,
      };
      await this.$insertapi("importlog", importlogPayload);
      const interval = setInterval(() => this.getResult(importlogPayload.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
      const result = await this.$insertapi(
        this.setting.call_api || this.setting.api,
        filter,
        undefined,
        importlogPayload.code,
      );
      this.isloading = false;
      clearInterval(interval);
      this.getResult(importlogPayload.code);

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

      let hasError = false;
      const 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) {
      const found = this.$findapi("importlog");
      found.params.filter = { code: logcode };
      const rs = await this.$getapi([found]);
      this.result = rs[0].data.rows[0];
    },

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