<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>