<template>
  <div class="app-container">
    <el-card shadow="never">
      <el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
        <el-form-item prop="monitorName">
          <template slot="label">{{ vsT("queryMonitorName") }}</template>
          <el-input
            v-model="queryParams.monitorName"
            :placeholder="vsT('queryMonitorNamePh')"
            clearable
            style="width: 220px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item prop="queryOwnerKey">
          <template slot="label">{{ vsT("queryOwner") }}</template>
          <el-select
            v-model="queryOwnerKey"
            filterable
            remote
            reserve-keyword
            clearable
            :placeholder="vsT('queryOwnerPh')"
            :remote-method="searchOwner"
            :loading="ownerLoading"
            style="width: 280px"
            @focus="searchOwner('')"
          >
            <el-option
              v-for="item in ownerOptions"
              :key="ownerOptionKey(item)"
              :label="ownerOptionLabel(item)"
              :value="ownerOptionKey(item)"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ vsCommon("search") }}</el-button>
          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ vsCommon("reset") }}</el-button>
          <el-button
            v-hasPermi="['videoSurveillance:livestockMonitor:sync']"
            type="warning"
            plain
            icon="el-icon-refresh"
            size="mini"
            :loading="syncing"
            @click="handleSync"
          >{{ vsT("btnSync") }}</el-button>
          <!-- 新增（暂隐藏）
          <el-button
            v-hasPermi="['videoSurveillance:livestockMonitor:add']"
            type="primary"
            plain
            icon="el-icon-plus"
            size="mini"
            @click="handleAdd"
          >{{ vsCommon("add") }}</el-button>
          -->
        </el-form-item>
      </el-form>
      <div v-if="lastSyncHint" class="livestock-monitor__sync-hint">{{ lastSyncHint }}</div>
    </el-card>

    <br />

    <el-card shadow="never">
      <el-table v-loading="loading" :data="tableList" border>
        <el-table-column :label="vsT('colMonitorName')" prop="monitorName" align="center" min-width="120" :show-overflow-tooltip="true" />
        <el-table-column :label="vsT('colOwner')" align="center" min-width="200" :show-overflow-tooltip="true">
          <template slot-scope="scope">
            <el-tag v-if="scope.row.ownerType" :type="ownerTypeTagType(scope.row.ownerType)" size="mini" class="owner-type-tag">
              {{ ownerTypeName(scope.row.ownerType) }}
            </el-tag>
            <span>{{ scope.row.ownerName || dash }}</span>
          </template>
        </el-table-column>
        <el-table-column :label="vsT('colInstallLocation')" prop="installLocation" align="center" min-width="120" :show-overflow-tooltip="true" />
        <el-table-column :label="vsCommon('colOp')" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
          <template slot-scope="scope">
            <el-button
              v-hasPermi="['videoSurveillance:livestockMonitor:query']"
              type="text"
              size="mini"
              @click="handleLiveView(scope.row)"
            >{{ vsT("actionLiveView") }}</el-button>
            <el-button
              v-hasPermi="['videoSurveillance:livestockMonitor:query']"
              type="text"
              size="mini"
              @click="handleView(scope.row)"
            >{{ vsCommon("view") }}</el-button>
            <!-- 编辑、删除（暂隐藏）
            <el-button
              v-hasPermi="['videoSurveillance:livestockMonitor:edit']"
              type="text"
              size="mini"
              @click="handleEdit(scope.row)"
            >{{ vsCommon("edit") }}</el-button>
            <el-button
              v-hasPermi="['videoSurveillance:livestockMonitor:remove']"
              type="text"
              size="mini"
              @click="handleDelete(scope.row)"
            >{{ vsCommon("delete") }}</el-button>
            -->
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
        :total="total"
        :page.sync="queryParams.pageNum"
        :limit.sync="queryParams.pageSize"
        @pagination="getList"
      />
    </el-card>

    <!-- 新增/编辑弹窗（暂隐藏）
    <el-dialog :title="dialogTitle" :visible.sync="open" width="620px" append-to-body @close="cancel">
      <el-form :key="formKey" ref="form" :model="form" label-width="110px">
        <el-form-item prop="monitorId" :rules="formRules.monitorId">
          <template slot="label">{{ vsT("formMonitorId") }}</template>
          <el-input v-model="form.monitorId" :placeholder="vsT('phMonitorId')" maxlength="32" show-word-limit />
        </el-form-item>
        <el-form-item prop="monitorName" :rules="formRules.monitorName">
          <template slot="label">{{ vsT("formMonitorName") }}</template>
          <el-input v-model="form.monitorName" :placeholder="vsT('phMonitorName')" maxlength="10" show-word-limit />
        </el-form-item>
        <el-form-item prop="ownerSelectKey" :rules="formRules.ownerSelectKey">
          <template slot="label">{{ vsT("formOwner") }}</template>
          <el-select
            v-model="form.ownerSelectKey"
            filterable
            remote
            reserve-keyword
            clearable
            :placeholder="vsT('phOwner')"
            :remote-method="searchOwner"
            :loading="ownerLoading"
            style="width: 100%"
            @focus="searchOwner('')"
          >
            <el-option
              v-for="item in ownerOptions"
              :key="ownerOptionKey(item)"
              :label="ownerOptionLabel(item)"
              :value="ownerOptionKey(item)"
            />
          </el-select>
        </el-form-item>
        <el-form-item prop="enclosureName" :rules="formRules.enclosureName">
          <template slot="label">{{ vsT("formEnclosureName") }}</template>
          <el-input v-model="form.enclosureName" :placeholder="vsT('phEnclosureName')" maxlength="64" show-word-limit />
        </el-form-item>
        <el-form-item prop="installLocation" :rules="formRules.installLocation">
          <template slot="label">{{ vsT("formInstallLocation") }}</template>
          <el-input v-model="form.installLocation" :placeholder="vsT('phInstallLocation')" maxlength="10" show-word-limit />
        </el-form-item>
        <el-form-item prop="videoSource" :rules="formRules.videoSource">
          <template slot="label">{{ vsT("formVideoSource") }}</template>
          <el-select v-model="form.videoSource" :placeholder="vsT('phVideoSource')" style="width: 100%">
            <el-option
              v-for="item in videoSourceOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">{{ vsCommon("ok") }}</el-button>
        <el-button @click="cancel">{{ vsCommon("cancel") }}</el-button>
      </div>
    </el-dialog>
    -->

    <el-dialog :title="vsCommon('viewTitle')" :visible.sync="viewOpen" width="620px" append-to-body>
      <el-form label-width="110px" size="small">
        <el-form-item :label="vsT('viewMonitorId')">
          <span>{{ viewRow.monitorId || dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewMonitorName')">
          <span>{{ viewRow.monitorName || dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewOwner')">
          <el-tag v-if="viewRow.ownerType" :type="ownerTypeTagType(viewRow.ownerType)" size="mini" class="owner-type-tag">
            {{ ownerTypeName(viewRow.ownerType) }}
          </el-tag>
          <span>{{ viewRow.ownerName || dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewEnclosureName')">
          <span>{{ viewRow.enclosureName || dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewInstallLocation')">
          <span>{{ viewRow.installLocation || dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewVideoSource')">
          <span>{{ viewRow.videoSourceName || videoSourceLabel(viewRow.videoSource) }}</span>
        </el-form-item>
        <el-form-item :label="vsCommon('colCreate')">
          <span>{{ viewRow.createTime ? parseTime(viewRow.createTime) : dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewCreateBy')">
          <span>{{ viewRow.createBy || dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewUpdateBy')">
          <span>{{ viewRow.updateBy || dash }}</span>
        </el-form-item>
        <el-form-item :label="vsT('viewUpdateTime')">
          <span>{{ viewRow.updateTime ? parseTime(viewRow.updateTime) : dash }}</span>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <!-- 编辑（暂隐藏）
        <el-button
          v-hasPermi="['videoSurveillance:livestockMonitor:edit']"
          type="primary"
          @click="handleEditFromView"
        >{{ vsCommon("edit") }}</el-button>
        -->
        <el-button @click="viewOpen = false">{{ vsCommon("close") }}</el-button>
      </div>
    </el-dialog>

    <el-dialog
      :title="liveDialogTitle"
      :visible.sync="liveOpen"
      width="960px"
      append-to-body
      destroy-on-close
      @close="closeLiveView"
    >
      <div v-loading="liveLoading" class="live-player-wrap">
        <EzvizHlsPlayer v-if="liveVideoUrl" :key="liveVideoUrl" :url="liveVideoUrl" @error="onLivePlayerError" />
        <div v-else-if="!liveLoading" class="live-player-empty">{{ vsT("msgLiveNoStream") }}</div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="closeLiveView">{{ vsCommon("close") }}</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import EzvizHlsPlayer from "@/components/EzvizHlsPlayer/index.vue"
import videoSurveillanceLocaleMixin from "@/mixins/videoSurveillanceLocaleMixin"
import {
  listLivestockMonitor,
  getLivestockMonitor,
  addLivestockMonitor,
  updateLivestockMonitor,
  delLivestockMonitor,
  listLivestockMonitorOwnerOptions,
  syncLivestockMonitor,
  getLivestockMonitorPlayUrl
} from "@/api/videoSurveillance/livestockMonitor"

const VIDEO_SOURCE_VALUES = ["wvp", "ys7", "url"]

function createEmptyForm() {
  return {
    id: undefined,
    monitorId: undefined,
    monitorName: undefined,
    ownerSelectKey: undefined,
    enclosureName: undefined,
    installLocation: undefined,
    videoSource: undefined
  }
}

export default {
  name: "VideoSurveillanceLivestockMonitor",
  components: {
    EzvizHlsPlayer
  },
  mixins: [videoSurveillanceLocaleMixin],
  data() {
    return {
      vsNs: "livestockMonitor",
      loading: false,
      syncing: false,
      liveLoading: false,
      open: false,
      viewOpen: false,
      liveOpen: false,
      liveRow: {},
      liveVideoUrl: "",
      liveVideoTitle: "",
      viewRow: {},
      dialogEdit: false,
      formKey: 0,
      total: 0,
      tableList: [],
      ownerOptions: [],
      ownerLoading: false,
      ownerSearchTimer: null,
      queryOwnerKey: undefined,
      lastSyncHint: "",
      queryParams: {
        pageNum: 1,
        pageSize: 20,
        monitorName: undefined,
        ownerType: undefined,
        ownerId: undefined
      },
      form: createEmptyForm()
    }
  },
  computed: {
    dash() {
      return this.$t("videoSurveillance.status.dash")
    },
    dialogTitle() {
      return this.dialogEdit ? this.vsT("dialogEdit") : this.vsT("dialogAdd")
    },
    liveDialogTitle() {
      const name = this.liveRow.monitorName || this.liveVideoTitle
      return name ? `${this.vsT("dialogLiveView")} - ${name}` : this.vsT("dialogLiveView")
    },
    videoSourceOptions() {
      return VIDEO_SOURCE_VALUES.map((value) => ({
        value,
        label: this.videoSourceLabel(value)
      }))
    },
    formRules() {
      return {
        monitorId: [
          { required: true, message: this.vsT("ruleMonitorIdRequired"), trigger: "blur" },
          { validator: this.validateMonitorId, trigger: "blur" }
        ],
        monitorName: [
          { required: true, message: this.vsT("ruleMonitorNameRequired"), trigger: "blur" },
          { validator: this.validateMonitorName, trigger: "blur" }
        ],
        ownerSelectKey: [{ validator: this.validateOwnerSelect, trigger: "change" }],
        enclosureName: [{ validator: this.validateEnclosureName, trigger: "blur" }],
        installLocation: [{ validator: this.validateInstallLocation, trigger: "blur" }],
        videoSource: [{ required: true, message: this.vsT("ruleVideoSourceRequired"), trigger: "change" }]
      }
    }
  },
  created() {
    this.getList()
  },
  beforeDestroy() {
    if (this.ownerSearchTimer) {
      clearTimeout(this.ownerSearchTimer)
    }
  },
  methods: {
    videoSourceLabel(value) {
      if (value === "wvp") {
        return this.$t("videoSurveillance.status.videoSourceWvp")
      }
      if (value === "ys7") {
        return this.$t("videoSurveillance.status.videoSourceYs7")
      }
      if (value === "url") {
        return this.$t("videoSurveillance.status.videoSourceUrl")
      }
      return value || this.dash
    },
    ownerTypeName(ownerType) {
      if (ownerType === 1) {
        return this.$t("videoSurveillance.status.ownerType1")
      }
      if (ownerType === 2) {
        return this.$t("videoSurveillance.status.ownerType2")
      }
      return this.dash
    },
    ownerOptionKey(item) {
      return `${item.ownerType}-${item.ownerId}`
    },
    ownerOptionLabel(item) {
      const typeName = item.ownerTypeName || this.ownerTypeName(item.ownerType)
      return `[${typeName}] ${item.ownerName || ""}`
    },
    parseOwnerKey(key) {
      if (!key) {
        return { ownerType: undefined, ownerId: undefined }
      }
      const idx = String(key).indexOf("-")
      if (idx < 0) {
        return { ownerType: undefined, ownerId: undefined }
      }
      return {
        ownerType: parseInt(String(key).slice(0, idx), 10),
        ownerId: parseInt(String(key).slice(idx + 1), 10)
      }
    },
    ensureOwnerOptionInList(ownerType, ownerId, ownerName, ownerTypeName) {
      if (ownerType == null || ownerId == null) {
        return
      }
      const key = `${ownerType}-${ownerId}`
      if (this.ownerOptions.some((o) => this.ownerOptionKey(o) === key)) {
        return
      }
      this.ownerOptions = [
        {
          ownerType,
          ownerId,
          ownerName: ownerName || "",
          ownerTypeName: ownerTypeName || this.ownerTypeName(ownerType)
        },
        ...this.ownerOptions
      ]
    },
    searchOwner(keyword) {
      if (this.ownerSearchTimer) {
        clearTimeout(this.ownerSearchTimer)
      }
      this.ownerSearchTimer = setTimeout(() => {
        this.ownerLoading = true
        const kw = keyword != null ? String(keyword).trim() : ""
        listLivestockMonitorOwnerOptions({ keyword: kw || undefined })
          .then((res) => {
            this.ownerOptions = Array.isArray(res.data) ? res.data : []
          })
          .finally(() => {
            this.ownerLoading = false
          })
      }, 300)
    },
    validateMonitorId(rule, value, callback) {
      const text = value != null ? String(value).trim() : ""
      if (!text) {
        callback(new Error(this.vsT("ruleMonitorIdRequired")))
        return
      }
      if (text.length > 32) {
        callback(new Error(this.vsT("ruleMonitorIdLen")))
        return
      }
      callback()
    },
    validateMonitorName(rule, value, callback) {
      const text = value != null ? String(value).trim() : ""
      if (!text) {
        callback(new Error(this.vsT("ruleMonitorNameRequired")))
        return
      }
      if (text.length > 10) {
        callback(new Error(this.vsT("ruleMonitorNameLen")))
        return
      }
      callback()
    },
    validateOwnerSelect(rule, value, callback) {
      if (!value) {
        callback()
        return
      }
      const parsed = this.parseOwnerKey(value)
      if (
        parsed.ownerType == null ||
        isNaN(parsed.ownerType) ||
        parsed.ownerId == null ||
        isNaN(parsed.ownerId)
      ) {
        callback(new Error(this.vsT("ruleOwnerIncomplete")))
        return
      }
      callback()
    },
    validateEnclosureName(rule, value, callback) {
      const text = value != null ? String(value).trim() : ""
      if (text.length > 64) {
        callback(new Error(this.vsT("ruleEnclosureNameLen")))
        return
      }
      callback()
    },
    validateInstallLocation(rule, value, callback) {
      const text = value != null ? String(value).trim() : ""
      if (text.length > 10) {
        callback(new Error(this.vsT("ruleInstallLocationLen")))
        return
      }
      callback()
    },
    buildListQuery() {
      const q = {
        pageNum: this.queryParams.pageNum,
        pageSize: this.queryParams.pageSize
      }
      const name = this.queryParams.monitorName != null ? String(this.queryParams.monitorName).trim() : ""
      if (name) {
        q.monitorName = name
      }
      const parsed = this.parseOwnerKey(this.queryOwnerKey)
      if (parsed.ownerType != null && !isNaN(parsed.ownerType) && parsed.ownerId != null && !isNaN(parsed.ownerId)) {
        q.ownerType = parsed.ownerType
        q.ownerId = parsed.ownerId
      }
      return q
    },
    buildPayload() {
      const parsed = this.parseOwnerKey(this.form.ownerSelectKey)
      const payload = {
        monitorId: String(this.form.monitorId).trim(),
        monitorName: String(this.form.monitorName).trim(),
        videoSource: this.form.videoSource
      }
      if (parsed.ownerType != null && !isNaN(parsed.ownerType) && parsed.ownerId != null && !isNaN(parsed.ownerId)) {
        payload.ownerType = parsed.ownerType
        payload.ownerId = parsed.ownerId
      }
      const enclosureName = this.form.enclosureName != null ? String(this.form.enclosureName).trim() : ""
      if (enclosureName) {
        payload.enclosureName = enclosureName
      }
      const installLocation = this.form.installLocation != null ? String(this.form.installLocation).trim() : ""
      if (installLocation) {
        payload.installLocation = installLocation
      }
      return payload
    },
    resetFormModel() {
      this.form = createEmptyForm()
    },
    fillFormFromData(data) {
      const ownerSelectKey =
        data.ownerType != null && data.ownerId != null ? `${data.ownerType}-${data.ownerId}` : undefined
      this.ensureOwnerOptionInList(data.ownerType, data.ownerId, data.ownerName, data.ownerTypeName)
      this.form = Object.assign(createEmptyForm(), {
        id: data.id,
        monitorId: data.monitorId,
        monitorName: data.monitorName,
        ownerSelectKey,
        enclosureName: data.enclosureName,
        installLocation: data.installLocation,
        videoSource: data.videoSource
      })
    },
    getList() {
      this.loading = true
      listLivestockMonitor(this.buildListQuery())
        .then((res) => {
          this.tableList = res.rows || []
          this.total = res.total != null ? res.total : 0
        })
        .finally(() => {
          this.loading = false
        })
    },
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    resetQuery() {
      this.queryParams.monitorName = undefined
      this.queryParams.ownerType = undefined
      this.queryParams.ownerId = undefined
      this.queryOwnerKey = undefined
      this.resetForm("queryForm")
      this.handleQuery()
    },
    handleAdd() {
      this.formKey += 1
      this.resetFormModel()
      this.dialogEdit = false
      this.open = true
      this.searchOwner("")
      this.$nextTick(() => {
        if (this.$refs.form) {
          this.$refs.form.clearValidate()
        }
      })
    },
    handleEdit(row) {
      getLivestockMonitor(row.id).then((res) => {
        const data = res.data || {}
        this.formKey += 1
        this.dialogEdit = true
        this.fillFormFromData(data)
        this.open = true
        this.viewOpen = false
        this.searchOwner(data.ownerName || "")
        this.$nextTick(() => {
          if (this.$refs.form) {
            this.$refs.form.clearValidate()
          }
        })
      })
    },
    handleEditFromView() {
      this.handleEdit(this.viewRow)
    },
    handleView(row) {
      getLivestockMonitor(row.id).then((res) => {
        this.viewRow = res.data || {}
        this.viewOpen = true
      })
    },
    handleLiveView(row) {
      if (!row || !row.monitorId) {
        this.$modal.msgWarning(this.vsT("msgLiveNoMonitorId"))
        return
      }
      this.liveRow = row
      this.liveVideoTitle = row.monitorName || ""
      this.liveVideoUrl = ""
      this.liveOpen = true
      this.liveLoading = true
      getLivestockMonitorPlayUrl(row.monitorId)
        .then((res) => {
          const data = res.data || {}
          this.liveVideoUrl = data.videoUrl ? String(data.videoUrl).trim() : ""
          if (data.monitorName) {
            this.liveVideoTitle = data.monitorName
            this.liveRow = Object.assign({}, row, { monitorName: data.monitorName })
          }
        })
        .catch(() => {})
        .finally(() => {
          this.liveLoading = false
        })
    },
    closeLiveView() {
      this.liveVideoUrl = ""
      this.liveVideoTitle = ""
      this.liveRow = {}
      this.liveOpen = false
      this.liveLoading = false
    },
    onLivePlayerError() {
      this.$modal.msgError(this.vsT("msgLivePlayFail"))
    },
    handleSync() {
      this.runSyncWithLoading(() => syncLivestockMonitor())
        .then((res) => {
          const data = res.data || {}
          this.$modal.msgSuccess(
            this.vsT("syncSummary", {
              insert: data.insertCount != null ? data.insertCount : 0,
              update: data.updateCount != null ? data.updateCount : 0,
              fail: data.failCount != null ? data.failCount : 0
            })
          )
          if (data.failCount > 0 && data.failMessages && data.failMessages.length) {
            this.$modal.msgWarning(data.failMessages.join("；"))
          }
          if (data.syncTime) {
            this.lastSyncHint = this.vsT("syncTimeHint", { time: this.parseTime(data.syncTime) })
          }
          this.getList()
        })
        .catch(() => {})
    },
    handleDelete(row) {
      this.$modal
        .confirm(this.vsT("confirmDelete"))
        .then(() => delLivestockMonitor(row.id))
        .then(() => {
          this.$modal.msgSuccess(this.vsCommon("msgDelOk"))
          this.viewOpen = false
          this.getList()
        })
        .catch(() => {})
    },
    submitForm() {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return
        }
        const payload = this.buildPayload()
        if (this.dialogEdit) {
          payload.id = this.form.id
          updateLivestockMonitor(payload).then(() => {
            this.$modal.msgSuccess(this.vsCommon("msgModOk"))
            this.open = false
            this.getList()
          })
        } else {
          addLivestockMonitor(payload).then(() => {
            this.$modal.msgSuccess(this.vsCommon("msgAddOk"))
            this.open = false
            this.getList()
          })
        }
      })
    },
    cancel() {
      this.open = false
      this.resetFormModel()
    }
  }
}
</script>

<style scoped>
.owner-type-tag {
  margin-right: 6px;
  vertical-align: middle;
}

.livestock-monitor__sync-hint {
  margin-top: 8px;
  font-size: 12px;
  color: #909399;
}

.live-player-wrap {
  position: relative;
  display: flex;
  width: 100%;
  height: 540px;
  overflow: hidden;
  background: #000;
}

.live-player-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: #909399;
  font-size: 14px;
}
</style>
