<script setup lang="ts">
import { computed, markRaw } from 'vue';
import type { PaginationProps } from 'element-plus';
import { Calendar, Flag, Plus, TrendCharts, User } from '@element-plus/icons-vue';
import { formatDateRange, getExecutionStatusName, getExecutionStatusTagType } from '../shared';
import { useTaskPermissions } from '../composables/use-task-permissions';
import IconMdiAccountMultipleOutline from '~icons/mdi/account-multiple-outline';
import IconMdiCheckCircleOutline from '~icons/mdi/check-circle-outline';
import IconMdiCloseCircleOutline from '~icons/mdi/close-circle-outline';
import IconMdiPause from '~icons/mdi/pause';
import IconMdiPencilOutline from '~icons/mdi/pencil-outline';
import IconMdiPlay from '~icons/mdi/play';
import IconMdiRestart from '~icons/mdi/restart';
import IconMdiSync from '~icons/mdi/sync';

defineOptions({ name: 'ProjectExecutionListPanel' });

type ExecutionStatusFilter = string | null;

interface Props {
  data: Api.Project.ProjectExecution[];
  loading: boolean;
  pagination: Partial<PaginationProps & Record<string, any>>;
  selectedId: string | null;
  statusBoard: Api.Project.StatusBoard | null;
  selectedStatus: ExecutionStatusFilter;
  ownerOptions: Api.SystemManage.UserSimple[];
  canCreate: boolean;
}

const { canEditExecution, canDeleteExecution, canSeeExecutionAssigneeEntry } = useTaskPermissions();

const props = defineProps<Props>();

interface Emits {
  (e: 'select', row: Api.Project.ProjectExecution): void;
  (e: 'status-change', status: ExecutionStatusFilter): void;
  (e: 'create'): void;
  (e: 'edit', row: Api.Project.ProjectExecution): void;
  (e: 'view', row: Api.Project.ProjectExecution): void;
  (e: 'members', row: Api.Project.ProjectExecution): void;
  (e: 'delete', row: Api.Project.ProjectExecution): void;
  (e: 'search'): void;
  (e: 'reset'): void;
  (
    e: 'status-action',
    row: Api.Project.ProjectExecution,
    action: Api.Project.LifecycleAction<Api.Project.ProjectExecutionActionCode> | null
  ): void;
}

const emit = defineEmits<Emits>();

const searchModel = defineModel<Api.Project.ProjectExecutionSearchParams>('searchModel', { required: true });

function handleSearch() {
  emit('search');
}

function handleKeywordInput(value: string) {
  searchModel.value.keyword = value.trim() || undefined;
}

function handleKeywordClear() {
  searchModel.value.keyword = undefined;
  handleSearch();
}

function handleOwnerSelect(id: string | null | undefined) {
  searchModel.value.ownerId = id || undefined;
  handleSearch();
}

function handleReset() {
  emit('reset');
}

const paginationVisible = computed(() => {
  const total = Number(props.pagination.total || 0);

  return total > 0;
});

const totalCount = computed(() => props.statusBoard?.total ?? 0);

const statusItems = computed(() => [
  {
    key: null,
    label: '全部',
    count: totalCount.value
  },
  ...(props.statusBoard?.items ?? []).map(item => ({
    key: item.statusCode,
    label: item.statusName,
    count: item.count
  }))
]);

function handleStatusClick(status: ExecutionStatusFilter) {
  emit('status-change', status);
}

function handleSelect(row: Api.Project.ProjectExecution) {
  emit('select', row);
}

function handlePageChange(page: number) {
  props.pagination['current-change']?.(page);
}

function handleSizeChange(pageSize: number) {
  props.pagination['size-change']?.(pageSize);
}

interface ExecutionAction {
  key: string;
  tooltip: string;
  icon: object;
  type: 'primary' | 'success' | 'danger' | 'warning';
  onClick: () => void;
}

const STATUS_ACTION_ICON_MAP: Record<string, object> = {
  start: markRaw(IconMdiPlay),
  pause: markRaw(IconMdiPause),
  resume: markRaw(IconMdiRestart),
  cancel: markRaw(IconMdiCloseCircleOutline),
  complete: markRaw(IconMdiCheckCircleOutline)
};

// 状态推进按钮 type 映射：cancel 破坏性=红，pause 中断=橙，complete 完结=绿，resume/start 主动作=蓝
const STATUS_ACTION_TYPE_MAP: Record<string, ExecutionAction['type']> = {
  cancel: 'danger',
  pause: 'warning',
  complete: 'success',
  resume: 'primary',
  start: 'primary'
};

// 同一状态下多个推进按钮的展示顺序：暂停 → 取消 → 完成 → 恢复 → 开始
const STATUS_ACTION_ORDER: Record<string, number> = {
  pause: 1,
  cancel: 2,
  complete: 3,
  resume: 4,
  start: 5
};

function createActions(row: Api.Project.ProjectExecution): ExecutionAction[] {
  const actions: ExecutionAction[] = [];

  // 查看入口已收到执行名称（点击名称触发 view）；操作区不再放眼睛按钮。

  // 编辑执行：pending/active + (权限码 OR 字段身份)
  if (canEditExecution(row)) {
    actions.push({
      key: 'edit',
      tooltip: '编辑',
      icon: markRaw(IconMdiPencilOutline),
      type: 'primary',
      onClick: () => emit('edit', row)
    });
  }

  // 协办人入口：仅项目负责人 / 项目创建人 / 执行负责人可见，无状态前置
  // 普通登录用户通过"查看"对话框看团队信息；dialog 内"加 / 移 / 换 owner"再自判 isMutable
  if (canSeeExecutionAssigneeEntry(row)) {
    actions.push({
      key: 'members',
      tooltip: '协办人',
      icon: markRaw(IconMdiAccountMultipleOutline),
      type: 'primary',
      onClick: () => emit('members', row)
    });
  }

  // 状态推进按钮完全依赖 availableActions（owner-only 字段硬卡，spec §3.4.1）
  // 前端只控制展示顺序与 type/icon，不参与判定哪些动作可见
  const sortedActions = [...row.availableActions].sort(
    (a, b) => (STATUS_ACTION_ORDER[a.actionCode] ?? 99) - (STATUS_ACTION_ORDER[b.actionCode] ?? 99)
  );
  sortedActions.forEach(action => {
    actions.push({
      key: action.actionCode,
      tooltip: action.actionName,
      icon: markRaw(STATUS_ACTION_ICON_MAP[action.actionCode] ?? IconMdiSync),
      type: STATUS_ACTION_TYPE_MAP[action.actionCode] ?? 'primary',
      onClick: () => emit('status-action', row, action)
    });
  });

  return actions;
}
</script>

<template>
  <section class="execution-list-panel">
    <header class="execution-list-panel__header">
      <h3 class="execution-list-panel__title">执行池</h3>
      <ElButton v-if="canCreate" type="primary" :icon="Plus" @click="emit('create')">新增</ElButton>
    </header>

    <div class="execution-list-panel__search">
      <ElInput
        :model-value="searchModel.keyword ?? ''"
        class="execution-search-input"
        placeholder="搜索执行名称"
        @update:model-value="handleKeywordInput"
        @keyup.enter="handleSearch"
      >
        <template #suffix>
          <ElIcon v-if="searchModel.keyword" class="execution-search-input__clear" @click="handleKeywordClear">
            <icon-mdi-close-circle />
          </ElIcon>
        </template>
      </ElInput>

      <ElSelect
        :model-value="searchModel.ownerId ?? null"
        class="execution-owner-select"
        placeholder="负责人"
        clearable
        filterable
        @change="handleOwnerSelect"
      >
        <ElOption v-for="item in ownerOptions" :key="item.id" :label="item.nickname" :value="item.id" />
      </ElSelect>

      <div class="execution-search__icons">
        <ElTooltip content="重置" placement="top">
          <ElButton link class="execution-search-input__btn" @click="handleReset">
            <icon-mdi-refresh class="text-15px" />
          </ElButton>
        </ElTooltip>
        <ElTooltip content="搜索" placement="top">
          <ElButton link class="execution-search-input__btn" type="primary" @click="handleSearch">
            <icon-ic-round-search class="text-15px" />
          </ElButton>
        </ElTooltip>
      </div>
    </div>

    <div class="execution-status-grid" aria-label="执行状态筛选">
      <button
        v-for="item in statusItems"
        :key="item.key || 'all'"
        type="button"
        class="execution-status-grid__item"
        :class="{ 'is-active': selectedStatus === item.key }"
        :aria-pressed="selectedStatus === item.key"
        @click="handleStatusClick(item.key)"
      >
        <span>{{ item.label }}</span>
        <strong>{{ item.count }}</strong>
      </button>
    </div>

    <ElScrollbar class="execution-list-panel__scrollbar">
      <ElSkeleton v-if="loading" :rows="5" animated />
      <ElEmpty v-else-if="data.length === 0" class="execution-list-panel__empty" description="暂无执行项" />
      <div v-else class="execution-list-panel__list">
        <article
          v-for="row in data"
          :key="row.id"
          class="execution-item"
          :class="{ 'is-active': selectedId === row.id }"
          @click="handleSelect(row)"
        >
          <div class="execution-item__main">
            <div class="execution-item__top">
              <strong
                class="execution-item__name"
                role="button"
                tabindex="0"
                @click.stop="emit('view', row)"
                @keydown.enter.stop.prevent="emit('view', row)"
              >
                {{ row.executionName || '未命名执行' }}
              </strong>
              <ElTag
                class="execution-item__status-tag"
                :type="getExecutionStatusTagType(row.statusCode)"
                effect="light"
                size="small"
              >
                {{ getExecutionStatusName(row) }}
              </ElTag>

              <div class="execution-item__actions" @click.stop>
                <ElTooltip v-for="action in createActions(row)" :key="action.key" :content="action.tooltip">
                  <ElButton link :type="action.type" class="execution-action-btn" @click="action.onClick()">
                    <component :is="action.icon" class="text-14px" />
                  </ElButton>
                </ElTooltip>
                <ElTooltip v-if="canDeleteExecution(row)" content="删除">
                  <ElButton link type="danger" class="execution-action-btn" @click="emit('delete', row)">
                    <icon-mdi-delete-outline class="text-14px" />
                  </ElButton>
                </ElTooltip>
              </div>
            </div>

            <div class="execution-item__meta">
              <span>
                <ElIcon><User /></ElIcon>
                {{ row.ownerNickname || '未设置负责人' }}
              </span>
              <span>
                <ElIcon><Flag /></ElIcon>
                计划 {{ formatDateRange(row.plannedStartDate, row.plannedEndDate) }}
              </span>
              <span>
                <ElIcon><Calendar /></ElIcon>
                实际 {{ formatDateRange(row.actualStartDate, row.actualEndDate) }}
              </span>
              <span class="execution-item__progress-row">
                <ElIcon><TrendCharts /></ElIcon>
                <ElProgress class="execution-item__progress" :percentage="row.progressRate" :stroke-width="6" />
              </span>
            </div>
          </div>
        </article>
      </div>
    </ElScrollbar>

    <div v-if="paginationVisible" class="execution-list-panel__pagination">
      <ElPagination
        small
        background
        layout="total, prev, pager, next"
        v-bind="pagination"
        @current-change="handlePageChange"
        @size-change="handleSizeChange"
      />
    </div>
  </section>
</template>

<style scoped lang="scss">
.execution-list-panel {
  display: flex;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  gap: 12px;
  height: 100%;
  padding: 12px;
  border: 1px solid rgb(226 232 240 / 92%);
  border-radius: 8px;
  background-color: #fff;
}

.execution-list-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 40px;
}

.execution-list-panel__title {
  margin: 0;
  color: rgb(15 23 42 / 94%);
  font-size: 16px;
  font-weight: 700;
  line-height: 1.4;
}

.execution-list-panel__search {
  display: flex;
  align-items: center;
  gap: 8px;
}

.execution-search-input {
  width: 140px;
  flex: 0 0 auto;
}

.execution-search-input__clear {
  color: rgb(192 196 204);
  cursor: pointer;
  transition: color 0.2s ease;
}

.execution-search-input__clear:hover {
  color: rgb(144 147 153);
}

.execution-search__icons {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  margin-left: auto;
}

.execution-search-input__btn {
  width: 24px;
  min-width: 24px;
  height: 24px;
  padding: 0;
}

.execution-owner-select {
  width: 140px;
  flex: 0 0 auto;
}

.execution-search__icons :deep(.el-button + .el-button) {
  margin-left: 0;
}

.execution-status-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.execution-status-grid__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-width: 0;
  min-height: 40px;
  padding: 8px 10px;
  border: 1px solid rgb(226 232 240 / 92%);
  border-radius: 6px;
  background-color: rgb(248 250 252 / 80%);
  color: rgb(51 65 85 / 96%);
  cursor: pointer;
  transition:
    border-color 0.16s ease,
    background-color 0.16s ease,
    color 0.16s ease;
}

.execution-status-grid__item:hover {
  border-color: rgb(148 163 184 / 80%);
  background-color: #fff;
}

.execution-status-grid__item.is-active {
  border-color: rgb(64 158 255 / 68%);
  background-color: rgb(236 245 255 / 92%);
  color: var(--el-color-primary);
}

.execution-status-grid__item span {
  overflow: hidden;
  min-width: 0;
  font-size: 13px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.execution-status-grid__item strong {
  flex: 0 0 auto;
  font-size: 16px;
  font-weight: 700;
}

.execution-list-panel__scrollbar {
  min-height: 0;
  flex: 1;
}

.execution-list-panel__empty {
  padding: 32px 0;
}

.execution-list-panel__list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 4px;
}

.execution-list-panel__pagination {
  display: flex;
  justify-content: flex-end;
  padding-top: 4px;
  overflow: hidden;
}

.execution-item {
  min-width: 0;
  padding: 10px;
  border: 1px solid rgb(226 232 240 / 92%);
  border-radius: 6px;
  background-color: #fff;
  cursor: pointer;
  transition:
    border-color 0.16s ease,
    background-color 0.16s ease;
}

.execution-item:hover {
  border-color: rgb(148 163 184 / 76%);
  background-color: rgb(248 250 252 / 68%);
}

.execution-item.is-active {
  border-color: rgb(64 158 255 / 68%);
  background-color: rgb(236 245 255 / 78%);
}

.execution-item__main {
  min-width: 0;
  flex: 1;
}

.execution-item__top {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 8px;
  min-height: 24px;
}

.execution-item__status-tag {
  flex: 0 0 auto;
}

.execution-item__name {
  overflow: hidden;
  min-width: 0;
  color: rgb(15 23 42 / 94%);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.5;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.16s ease;
}

.execution-item__name:hover,
.execution-item__name:focus-visible {
  color: var(--el-color-primary);
  outline: none;
}

.execution-item__meta {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: 8px;
  color: rgb(100 116 139 / 94%);
  font-size: 12px;
  line-height: 1.5;
}

.execution-item__meta span {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  gap: 4px;
}

.execution-item__progress-row {
  width: 100%;
}

.execution-item__progress {
  flex: 1;
  min-width: 0;
}

.execution-item__actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  margin-left: auto;
}

.execution-item__actions :deep(.el-button + .el-button) {
  margin-left: 0;
}

:deep(.execution-action-btn) {
  padding: 3px;
  min-width: auto;
  height: auto;
  line-height: 1;
}

@media (width <= 1280px) {
  .execution-item__top {
    align-items: flex-start;
    flex-wrap: wrap;
  }

  .execution-item__actions {
    justify-content: flex-end;
  }
}
</style>
