<template>
  <div class="app-container" v-loading="loading">
    <evaluation-title :title="title" :sub-title="subTitle" nav-back-button></evaluation-title>
    <el-card>
      <mx-condition :query-params="queryParams" :require-fields="requireFields" :local-data="localData"
                    @query="handleQuery"></mx-condition>
    </el-card>
    <mx-table :rows="detailTable.rows" :prop-defines="detailTable.columns" border class="mt20 elective-flow-table">
      <template #pagedIndex="{$index}">
        {{ (queryParams.pageNum - 1) * queryParams.pageSize + $index + 1 }}
      </template>
      <template #group-header="{label, key}">
        <div class="fx-row jc-cen">
          <span>{{ label }}</span>
          <el-popover trigger="hover" :disabled="!!!detailTable.groupHeaders[key].text" class="mx-generation-rank">
            <div v-for="(desc,idx) in detailTable.groupHeaders[key].descriptions" :key="idx">
              <span>{{ desc.description }}</span> <span class="bold">{{ desc.value }}</span></div>
            <el-tag slot="reference" size="mini" class="round-y ml3">{{ detailTable.groupHeaders[key].text }}</el-tag>
          </el-popover>
        </div>
      </template>
      <template #studentName="{value, row}">
        <span :style="getStudentNameCellStyle(row)">{{ value }}</span>
      </template>
      <template #group-flow="{value}">
        <elective-flow-major v-if="value.matchedMajors.length" :icon-classes="['f-primary']"
                             :matched-majors="value.matchedMajors"></elective-flow-major>
        <div class="fx-row fx-cen-cen">
          <span v-if="value.text">{{ value.text }}</span>
          <span v-else v-html="'&#12288'"></span>
        </div>
        <elective-flow-rank-descriptor v-if="value.rankDescriptors"
                                       :rank-descriptors="value.rankDescriptors"></elective-flow-rank-descriptor>
      </template>
      <template #flow-action="{row}">
        <el-link v-if="enableStudentTableView(row)" @click="handleStudentTable(row)" :underline="false">查看</el-link>
        <el-link v-if="enableLogView(row)" @click="handleFlowLog(row)" :underline="false">查看</el-link>
        <el-popover v-if="row['enableForce']" :ref="'force_'+row['studentId']" width="80" trigger="click"
                    popper-class="zero-padding-popover">
          <div class="fx-column">
            <el-divider>调剂</el-divider>
            <el-button v-for="(g,i) in prevData.groups" :key="i" class="ml0" plain type="text"
                       :disabled="g.groupId==row['disableForceGroupId']"
                       @click="handleForceAdjust(g, row)&&$refs['force_'+row['studentId']].doClose()">{{ g.groupName }}
            </el-button>
          </div>
          <el-link slot="reference" :underline="false" type="warning" class="ml10">调剂</el-link>
        </el-popover>
      </template>
    </mx-table>
    <pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
                @pagination="loadGenerationDetails"></pagination>
    <el-dialog title="选科流程明细" v-if="logVisible" :visible.sync="logVisible" :width="logDialogWidth">
      <elective-generation-flow-log :groups="prevData.groups" :histories="logRow.histories"
                                    :matched-majors="this.majorsMap[logRow['studentId']]"/>
    </el-dialog>
    <el-dialog :title="'查看分析 '+activeOpt.title" :visible.sync="studentTableVisible" :width="logDialogWidth">
      <elective-ai-table :generation="studentGeneration" :optional-majors="studentMajors" readonly></elective-ai-table>
    </el-dialog>
  </div>
</template>

<script>
import config from '@/common/mx-config'
import consts from '@/common/mx-const'
import transferMixin from '@/components/mx-transfer-mixin'
import ElectiveToolsMixin from '@/views/elective/select/components/elective-tools-mixins'
import groupTranslateMixin from '@/components/Cache/modules/mx-select-translate-mixin'
import ElectiveColorMap from './components/elective-color-map-mixins'
import { mapGetters } from 'vuex'
import MxCondition from '@/components/MxCondition/mx-condition'
import {
  enrollByForce,
  getElectiveGenerationDetails,
  getGenerationOptionalMajorsBatch
} from '@/api/webApi/elective/generation'
import ElectiveGenerationFlowLog from '@/views/elective/generation/components/elective-generation-flow-log'
import ElectiveFlowMajor from '@/views/elective/generation/components/elective-flow-major'
import ElectiveFlowRankDescriptor from '@/views/elective/generation/components/elective-flow-rank-descriptor'
import { getStudentElectiveModels } from '@/api/webApi/elective/selected-subject'
import ElectiveAiTable from '@/views/elective/select/components/elective-ai-table'
import EventBus from '@/components/EventBus'

export default {
  components: {
    ElectiveAiTable,
    ElectiveFlowRankDescriptor,
    ElectiveFlowMajor,
    ElectiveGenerationFlowLog,
    MxCondition
  },
  mixins: [transferMixin, groupTranslateMixin, ElectiveColorMap, ElectiveToolsMixin],
  name: 'generation-detail',
  computed: {
    ...mapGetters(['school']),
    title() {
      const y = (this.prevData.year + '').tailingFix('学年')
      const s = this.school.schoolName
      const n = this.prevData.roundName
      return y + s + n
    },
    options() {
      return config.electiveGenerationOptions
    },
    activeOpt() {
      return Object.values(this.options).find(opt => opt.value == this.prevData.activeGeneration)
    },
    subTitle() {
      const hideGenerations = [this.options.init, this.options.terminate]
      let generationDesc = hideGenerations.includes(this.activeOpt) ? '' : this.activeOpt?.title || ''
      if (this.prevData.isAccumulate && generationDesc) generationDesc = this.options.primary.title + ' 至 ' + generationDesc
      return generationDesc
    },
    localData() {
      this.queryParams.generation = this.prevData.queryGeneration
      this.queryParams.generationQueryCode = this.prevData.queryCode
      this.queryParams.generationGroupId = this.prevData.queryGroupId
      return {
        ignoreGroupCategories: this.prevData.ignoreGroupCategories,
        categories: this.prevData.queryableCategories,
        groups: this.prevData.groups
      }
    },
    detailTable() {
      if (!this.majorsMap) return {}
      if (!this.prevData.queryableCategories.length) return {}
      if (!this.detailWrapper?.groupDescriptors?.length) return {}
      // fixed columns
      const queryCategory = this.prevData.queryableCategories.find(i => i.id == this.queryParams.generationQueryCode)
      const ignoreGroups = this.prevData.ignoreGroupCategories.includes(this.queryParams.generationQueryCode)
      const columns = {
        index: { label: '序号', slot: 'pagedIndex' },
        className: { label: '班级' },
        studentName: { label: '姓名', slot: 'studentName' },
        userName: { label: '账号' }
      }
      if (!ignoreGroups) {
        columns.groupName = { label: queryCategory.detailName || '组合' }
        columns.datetime = { label: '时间', minWidth: '110px' }
      }
      // extension generation columns & custom group header
      const rows = this.detailWrapper.details // todo: need clone?
      const groupHeaders = {}
      const groupKeyPrefix = 'group_'
      // if (!ignoreGroups) {
      this.prevData.groups.forEach(group => {
        const groupKey = groupKeyPrefix + group.groupId
        columns[groupKey] = {
          label: group.groupName,
          slotHeader: 'group-header',
          slot: 'group-flow',
          minWidth: '180px'
        }
        groupHeaders[groupKey] = this.getGroupHeaderDescription(group.groupId)
        rows.forEach(row => {
          row[groupKey] = this.getGroupDescription(row, group.groupId, this.majorsMap)
        })
      })
      // }
      // 初选报名不需要展示操作
      const actionHide = this.activeOpt?.value == this.options.primary.value
      columns.actions = { label: '操作', slot: 'flow-action', minWidth: '100px', hidden: actionHide }
      return {
        rows,
        columns,
        groupHeaders
      }
    },
    logDialogWidth() {
      const expectedWidth = (this.prevData.groups.length + 3) * 160 // 假定elective-generation-flow-log 单格宽160
      const finalWidth = Math.min(expectedWidth, window.innerWidth * 0.8)
      return finalWidth + 'px'
    }
  },
  data() {
    return {
      loading: false,
      requireFields: ['generationQueryCode'],
      queryParams: {
        pageNum: 1,
        pageSize: 20,
        generation: '',
        generationQueryCode: '',
        generationGroupId: ''
      },
      // query data
      total: 0,
      detailWrapper: null,
      majorsMap: null,
      // log
      logVisible: false,
      logRow: {},
      studentTableVisible: false,
      studentGeneration: {},
      studentMajors: []
    }
  },
  methods: {
    handleQuery() {
      this.queryParams.pageNum = 1
      this.loadGenerationDetails()
    },
    loadGenerationDetails() {
      const params = {
        pageNum: this.queryParams.pageNum,
        pageSize: this.queryParams.pageSize,
        roundId: this.prevData.roundId,
        generation: this.queryParams.generation,
        groupId: this.queryParams.generationGroupId,
        queryCode: this.queryParams.generationQueryCode,
        active: this.prevData.activeGeneration
      }
      this.loading = true
      this.majorsMap = null
      getElectiveGenerationDetails(params).then(res => {
        this.total = res['total'] || 0
        this.detailWrapper = res.data

        const studentIds = res.data.details?.map(d => d['studentId']).toString()
        if (!studentIds) return Promise.resolve({ data: {} })
        return getGenerationOptionalMajorsBatch({ studentIds })
      }).then(res => {
        this.majorsMap = res.data
      }).finally(() => this.loading = false)
    },
    getGroupHeaderDescription(groupId) {
      const statistic = this.detailWrapper.groupDescriptors.find(d => d.groupId == groupId)
      if (!statistic?.descriptors?.length) return {}
      const descriptors = statistic.descriptors //.reverse()
      return {
        text: descriptors.map(d => d.value).join('/'),
        descriptions: descriptors
      }
    },
    getGroupDescription(row, groupId) {
      const matchedMajors = (this.majorsMap[row['studentId']]
        ?.marjors?.filter(m => m['matchedGroupIds'].some(id => id == groupId)) || [])
        .groupBy(m => m.collegeName)
      const current = this.prevData.activeGeneration
      const options = Object.values(this.options)
      const histories = row['histories'] || []
      const filterHistories = []
      for (let g = current; g > 0; g--) {
        const opt = options.find(opt => opt.value == g)
        const groupHistories = histories.filter(h => h.generation == g && h.groupId == groupId)
        if (groupHistories.length) filterHistories.push(groupHistories)
        // if (g < current && opt.decisionMaking) break // TODO: 仅迭代至最近的决策代（可能需要调整）
      }
      if (!filterHistories.length) return { matchedMajors }
      filterHistories.reverse() // 还原顺序
      const mergedHistories = filterHistories.reduce((prev, cur) => {
        prev.push(...cur)
        return prev
      }, [])
      return {
        matchedMajors,
        text: mergedHistories.map(h => h.description).join('/'),
        histories: mergedHistories,
        rankDescriptors: mergedHistories.last(i => !!i.rankDescriptors?.length)?.rankDescriptors
      }
    },
    getStudentNameCellStyle(row) {
      const style = {}
      if (row.color) style.color = this.matchElectiveColor(row.color)
      return style
    },
    enableLogView(student) {
      return this.activeOpt?.value > this.options.primary.value
        && !this.enableStudentTableView(student)
    },
    enableStudentTableView(student) {
      return !this.isGroupEnrolled(student)
        && this.activeOpt?.value > this.options.primary.value
        && this.activeOpt?.value < this.options.forceAdjust.value
    },
    handleFlowLog(row) {
      this.logRow = row
      this.logVisible = true
    },
    handleStudentTable(row) {
      this.loading = true
      const query = {
        generation: this.activeOpt.value,
        studentId: row.studentId
      }
      const majors = this.majorsMap[query.studentId]?.marjors || []
      getStudentElectiveModels(query).then(res => {
        this.studentMajors = majors
        const generationModels = res.data?.filter(g => g.generation <= query.generation) || []
        this.initGenerationModels(generationModels, this.options)
        this.studentGeneration = {
          options: this.options,
          current: query.generation,
          currentOpt: this.activeOpt,
          active: query.generation,
          activeOpt: this.activeOpt,
          roundGroups: this.prevData.groups,
          models: generationModels,
          activeModels: generationModels,
          activeModel: generationModels.find(g => g.generation == query.generation)
        }
        this.studentTableVisible = true
      }).finally(() => this.loading = false)
    },
    handleForceAdjust(group, row) {
      let message = `确认将'${row.studentName}'调剂至'${group.groupName}'？！`
      if (row['disableForceGroupId'] > 0) {
        message += `\n 当前录取组合'${this.translateGroup(row['disableForceGroupId'])}'`
      }
      this.$confirm(message, '强制调剂提醒', { type: 'warning' }).then(() => {
        enrollByForce(group.groupId, row['studentId']).then(res => {
          this.loadGenerationDetails() // refresh
          EventBus.instance.$emit(consts.keys.electiveGlobalChangeEvent) // global notify for refresh data
        })
      })
      return true
    }
  }
}
</script>

<style>
@import url('./components/elective-flow-table-style.css');
</style>
