<script setup lang="ts">
/**
 * 项目配置页展示项目仓库、发布环境、Gitea 仓库诊断和真实 Jenkins job 诊断状态。
 */
import { Promotion, Refresh, Search } from '@element-plus/icons-vue'
import { computed, onMounted, ref } from 'vue'
import StatusPill from '../components/StatusPill.vue'
import { usePlatformStore } from '../stores/platform'
import type { EnvironmentStatus, HealthState, ProjectConfig, ProjectPermissionLevel } from '../types/devops'

const platform = usePlatformStore()
const diagnosticsLoading = ref(false)
const searchKeyword = ref('')
const readinessFilter = ref<ProjectReadinessState | ''>('')
const permissionFilter = ref<ProjectPermissionLevel | ''>('')

type ProjectReadinessState = 'ready' | 'attention' | 'blocked' | 'readonly'

const readinessOptions: Array<{ label: string; value: ProjectReadinessState }> = [
  { label: '可发布', value: 'ready' },
  { label: '需关注', value: 'attention' },
  { label: '有阻断', value: 'blocked' },
  { label: '只读', value: 'readonly' },
]

const permissionOptions: Array<{ label: string; value: ProjectPermissionLevel }> = [
  { label: '构建权限', value: 'build' },
  { label: '只读权限', value: 'read' },
]

const filteredProjects = computed(() => {
  const keyword = searchKeyword.value.trim().toLowerCase()

  return platform.projects.filter((project) => {
    if (readinessFilter.value && projectReadinessState(project) !== readinessFilter.value) {
      return false
    }

    if (permissionFilter.value && platform.projectPermissionLevel(project.key) !== permissionFilter.value) {
      return false
    }

    if (!keyword) {
      return true
    }

    return [
      project.name,
      project.key,
      project.serviceType,
      project.repository,
      project.defaultBranch,
      project.tagPolicy,
      project.permissionLevelName,
    ]
      .filter((value): value is string => typeof value === 'string' && value.length > 0)
      .some((value) => value.toLowerCase().includes(keyword))
  })
})

const projectOverview = computed(() => {
  const ready = platform.projects.filter((project) => projectReadinessState(project) === 'ready').length
  const attention = platform.projects.filter((project) => projectReadinessState(project) === 'attention').length
  const blocked = platform.projects.filter((project) => projectReadinessState(project) === 'blocked').length
  const readOnly = platform.projects.filter((project) => projectReadinessState(project) === 'readonly').length

  return [
    { key: 'total', label: '纳管项目', value: platform.projects.length, tone: 'neutral' },
    { key: 'ready', label: '可发布', value: ready, tone: 'success' },
    { key: 'attention', label: '需关注', value: attention, tone: attention > 0 ? 'warning' : 'neutral' },
    { key: 'blocked', label: '有阻断', value: blocked, tone: blocked > 0 ? 'danger' : 'neutral' },
    { key: 'readonly', label: '只读项目', value: readOnly, tone: readOnly > 0 ? 'muted' : 'neutral' },
  ]
})

const hasActiveFilters = computed(() => Boolean(
  searchKeyword.value.trim() ||
    readinessFilter.value ||
    permissionFilter.value,
))

onMounted(() => {
  void refreshProjectDiagnostics()
})

async function refreshProjectDiagnostics() {
  diagnosticsLoading.value = true

  try {
    await Promise.all([
      platform.loadProjectJenkinsDiagnostics(),
      platform.loadProjectGiteaDiagnostics(),
    ])
  } finally {
    diagnosticsLoading.value = false
  }
}

function lastBuildText(env: EnvironmentStatus): string {
  if (!env.jenkinsLastBuild?.number) {
    return '-'
  }

  if (env.jenkinsLastBuild.building) {
    return `#${env.jenkinsLastBuild.number} 运行中`
  }

  return `#${env.jenkinsLastBuild.number} ${env.jenkinsLastBuild.result || 'UNKNOWN'}`
}

function commitText(project: ProjectConfig): string {
  const commit = project.giteaLatestCommit

  if (!commit?.sha) {
    return '-'
  }

  const title = commit.message.split('\n')[0] || '无提交说明'
  return `${commit.sha.slice(0, 8)} · ${title}`
}

function branchTagText(project: ProjectConfig): string {
  if (project.giteaBranchCount === undefined && project.giteaTagCount === undefined) {
    return '尚未诊断'
  }

  const branchCount = project.giteaBranchCount ?? 0
  const tagCount = project.giteaTagCount ?? 0

  return `${branchCount} branches · ${tagCount} tags`
}

function webhookCountText(project: ProjectConfig): string {
  if (
    project.giteaWebhookHookCount === undefined &&
    project.giteaWebhookActivePushHookCount === undefined
  ) {
    return '尚未诊断'
  }

  return `${project.giteaWebhookActivePushHookCount ?? 0}/${project.giteaWebhookHookCount ?? 0} 个 active push hook`
}

function webhookHookText(hook: ProjectConfig['giteaWebhookHooks'][number]): string {
  const events = hook.events.length > 0 ? hook.events.join(', ') : '无事件'
  const branch = hook.branchFilter ? ` · ${hook.branchFilter}` : ''
  const matched = hook.matchesExpectedRelay ? ' · relay 匹配' : ''
  const active = hook.active ? '启用' : '停用'

  return `#${hook.id} ${hook.type} · ${active} · ${events}${branch}${matched}`
}

function projectReadinessState(project: ProjectConfig): ProjectReadinessState {
  if (projectHasBlockingIssue(project)) {
    return 'blocked'
  }

  if (projectHasWarningIssue(project)) {
    return 'attention'
  }

  if (!platform.canBuildProject(project.key)) {
    return 'readonly'
  }

  return 'ready'
}

function projectReadinessLabel(project: ProjectConfig): string {
  const state = projectReadinessState(project)

  if (state === 'ready') {
    return '可发布'
  }

  if (state === 'blocked') {
    return '有阻断'
  }

  if (state === 'readonly') {
    return '只读'
  }

  return '需关注'
}

function projectReadinessTagType(
  project: ProjectConfig,
): 'success' | 'warning' | 'danger' | 'info' {
  const state = projectReadinessState(project)

  if (state === 'ready') {
    return 'success'
  }

  if (state === 'blocked') {
    return 'danger'
  }

  return state === 'attention' ? 'warning' : 'info'
}

function projectReadinessSummary(project: ProjectConfig): string {
  const issues = projectIssueSummaries(project)

  if (issues.length > 0) {
    return issues[0]
  }

  if (!platform.canBuildProject(project.key)) {
    return '当前账号只有只读权限'
  }

  return 'Gitea、Jenkins、Webhook 和通知链路均未发现异常'
}

function projectIssueSummaries(project: ProjectConfig): string[] {
  const issues: string[] = []

  appendHealthIssue(issues, 'Gitea 仓库', project.giteaStatus, project.giteaMessage)
  appendHealthIssue(issues, 'Webhook / Relay', project.giteaWebhookStatus, project.giteaWebhookMessage)

  for (const env of project.environments) {
    appendHealthIssue(issues, `${env.label} Jenkins`, env.jenkinsStatus, env.jenkinsMessage)
  }

  appendHealthIssue(issues, '通知链路', project.integrations.wecom)

  return issues
}

function appendHealthIssue(
  issues: string[],
  label: string,
  state: HealthState,
  message?: string,
) {
  if (state === 'healthy') {
    return
  }

  const stateText = state === 'warning' ? '待配置' : state === 'offline' ? '离线' : '异常'
  issues.push(`${label}${message ? `：${message}` : `：${stateText}`}`)
}

function projectHasBlockingIssue(project: ProjectConfig): boolean {
  return projectHealthStates(project).some((state) => state === 'error' || state === 'offline')
}

function projectHasWarningIssue(project: ProjectConfig): boolean {
  return projectHealthStates(project).some((state) => state === 'warning')
}

function projectHealthStates(project: ProjectConfig): HealthState[] {
  return [
    project.giteaStatus,
    project.giteaWebhookStatus,
    project.integrations.wecom,
    ...project.environments.map((env) => env.jenkinsStatus),
  ]
}

function resetProjectFilters() {
  searchKeyword.value = ''
  readinessFilter.value = ''
  permissionFilter.value = ''
}
</script>

<template>
  <div class="page-shell">
    <div class="page-header">
      <div>
          <h1>项目配置</h1>
          <p>展示后端返回的项目、环境、Jenkins Job、Gitea 仓库和通知通道绑定关系。</p>
        </div>
      <div class="toolbar">
        <ElTag type="info" round>后端配置源</ElTag>
        <ElButton
          :icon="Refresh"
          type="primary"
          plain
          :loading="diagnosticsLoading"
          @click="refreshProjectDiagnostics"
        >
          刷新项目诊断
        </ElButton>
      </div>
    </div>

    <section class="project-overview-grid">
      <article
        v-for="item in projectOverview"
        :key="item.key"
        class="project-overview-card"
        :class="`tone-${item.tone}`"
      >
        <span>{{ item.label }}</span>
        <strong>{{ item.value }}</strong>
      </article>
    </section>

    <section class="panel">
      <div class="panel-header">
        <h2>项目清单</h2>
        <span>{{ filteredProjects.length }} / {{ platform.projects.length }} 个项目</span>
      </div>
      <div class="panel-body">
        <div class="project-filter-bar">
          <ElInput
            v-model="searchKeyword"
            clearable
            :prefix-icon="Search"
            placeholder="搜索项目 / 仓库 / 默认分支"
            class="project-search-input"
          />
          <ElSelect v-model="readinessFilter" clearable placeholder="发布态">
            <ElOption
              v-for="option in readinessOptions"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </ElSelect>
          <ElSelect v-model="permissionFilter" clearable placeholder="权限">
            <ElOption
              v-for="option in permissionOptions"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </ElSelect>
          <ElButton :disabled="!hasActiveFilters" @click="resetProjectFilters">
            重置筛选
          </ElButton>
        </div>
        <ElTable :data="filteredProjects" row-key="key" empty-text="没有符合条件的项目">
          <ElTableColumn type="expand">
            <template #default="{ row }">
              <div class="env-config">
                <div class="project-diagnostic-card">
                  <div class="env-config-head">
                    <strong>Gitea 仓库诊断</strong>
                    <StatusPill :state="row.giteaStatus" />
                  </div>
                  <dl>
                    <dt>仓库状态</dt>
                    <dd>
                      <StatusPill :state="row.giteaStatus" />
                      <span class="diagnostic-message">{{ row.giteaMessage }}</span>
                    </dd>
                    <dt>公开地址</dt>
                    <dd>
                      <a
                        v-if="row.giteaWebUrl"
                        :href="row.giteaWebUrl"
                        target="_blank"
                        rel="noreferrer"
                      >
                        {{ row.giteaWebUrl }}
                      </a>
                      <span v-else class="mono">{{ row.repository }}</span>
                    </dd>
                    <dt>默认分支</dt>
                    <dd>{{ row.giteaDefaultBranch || row.defaultBranch }}</dd>
                    <dt>分支 / Tag</dt>
                    <dd>{{ branchTagText(row) }}</dd>
                    <dt>默认分支 commit</dt>
                    <dd class="mono">{{ commitText(row) }}</dd>
                    <dt>Webhook / Relay</dt>
                    <dd>
                      <StatusPill :state="row.giteaWebhookStatus" />
                      <span class="diagnostic-message">{{ row.giteaWebhookMessage }}</span>
                    </dd>
                    <dt>Relay 目标</dt>
                    <dd class="mono">{{ row.giteaWebhookExpectedRelayTarget || '-' }}</dd>
                    <dt>Hook 数量</dt>
                    <dd>{{ webhookCountText(row) }}</dd>
                    <dt>Hook 明细</dt>
                    <dd>
                      <div v-if="row.giteaWebhookHooks.length > 0" class="webhook-hook-list">
                        <div
                          v-for="hook in row.giteaWebhookHooks"
                          :key="hook.id"
                          class="webhook-hook-item"
                        >
                          <span>{{ webhookHookText(hook) }}</span>
                          <small class="mono">{{ hook.target || '-' }}</small>
                        </div>
                      </div>
                      <span v-else>-</span>
                    </dd>
                  </dl>
                </div>
                <div v-for="env in row.environments" :key="env.name" class="env-config-card">
                  <div class="env-config-head">
                    <strong>{{ env.label }}</strong>
                    <StatusPill :state="env.status" />
                  </div>
                  <dl>
                    <dt>分支策略</dt>
                    <dd>{{ env.branchPolicy }}</dd>
                    <dt>Jenkins Job</dt>
                    <dd class="mono">{{ env.jenkinsJob }}</dd>
                    <dt>Job 状态</dt>
                    <dd>
                      <StatusPill :state="env.jenkinsStatus" />
                      <span class="diagnostic-message">{{ env.jenkinsMessage }}</span>
                    </dd>
                    <dt>最近构建</dt>
                    <dd>
                      <a
                        v-if="env.jenkinsLastBuild?.url"
                        :href="env.jenkinsLastBuild.url"
                        target="_blank"
                        rel="noreferrer"
                      >
                        {{ lastBuildText(env) }}
                      </a>
                      <span v-else>{{ lastBuildText(env) }}</span>
                    </dd>
                    <dt>通知通道</dt>
                    <dd>{{ env.wecomRobot }}</dd>
                    <dt>最近发布</dt>
                    <dd>
                      <div v-if="env.lastRunId !== '-'" class="latest-release">
                        <div class="latest-release-head">
                          <StatusPill :state="env.status" />
                          <RouterLink
                            class="run-link mono"
                            :to="{ name: 'runs', query: { runId: env.lastRunId } }"
                          >
                            {{ env.lastRunId }}
                          </RouterLink>
                        </div>
                        <small>
                          {{ env.version }} · {{ env.lastActor }} · {{ env.lastReleasedAt }}
                        </small>
                      </div>
                      <span v-else>暂无真实发布记录</span>
                    </dd>
                  </dl>
                </div>
              </div>
            </template>
          </ElTableColumn>
          <ElTableColumn prop="name" label="项目" min-width="150" />
          <ElTableColumn label="发布态" min-width="190">
            <template #default="{ row }">
              <div class="readiness-cell">
                <ElTag :type="projectReadinessTagType(row)" effect="light" round>
                  {{ projectReadinessLabel(row) }}
                </ElTag>
                <small>{{ projectReadinessSummary(row) }}</small>
              </div>
            </template>
          </ElTableColumn>
          <ElTableColumn label="权限" width="120">
            <template #default="{ row }">
              <ElTag :type="platform.canBuildProject(row.key) ? 'success' : 'info'" effect="plain" round>
                {{ platform.canBuildProject(row.key) ? '构建' : '只读' }}
              </ElTag>
            </template>
          </ElTableColumn>
          <ElTableColumn prop="serviceType" label="类型" min-width="130" />
          <ElTableColumn prop="repository" label="Gitea 仓库" min-width="320">
            <template #default="{ row }">
              <span class="mono">{{ row.repository }}</span>
            </template>
          </ElTableColumn>
          <ElTableColumn prop="defaultBranch" label="默认分支" width="120" />
          <ElTableColumn prop="tagPolicy" label="Tag 策略" min-width="220" />
          <ElTableColumn label="集成状态" width="280">
            <template #default="{ row }">
              <div class="status-tags">
                <StatusPill :state="row.integrations.jenkins" text="Jenkins" />
                <StatusPill :state="row.integrations.gitea" text="Gitea" />
                <StatusPill :state="row.integrations.wecom" text="通知" />
                <StatusPill :state="row.integrations.llm" text="LLM" />
              </div>
            </template>
          </ElTableColumn>
          <ElTableColumn label="操作" width="170" fixed="right">
            <template #default="{ row }">
              <div class="project-actions">
                <RouterLink
                  v-slot="{ navigate }"
                  custom
                  :to="{ name: 'releases', query: { projectKey: row.key } }"
                >
                  <ElButton
                    :icon="Promotion"
                    link
                    type="primary"
                    :disabled="!platform.canBuildProject(row.key)"
                    @click="navigate"
                  >
                    发布
                  </ElButton>
                </RouterLink>
                <RouterLink :to="{ name: 'runs', query: { projectKey: row.key } }">
                  <ElButton link type="primary">运行记录</ElButton>
                </RouterLink>
              </div>
            </template>
          </ElTableColumn>
        </ElTable>
      </div>
    </section>
  </div>
</template>

<style scoped>
.project-overview-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
}

.project-overview-card {
  min-width: 0;
  padding: 12px 14px;
  border: 1px solid #d8e2ef;
  border-radius: 8px;
  background: #fff;
}

.project-overview-card span {
  display: block;
  color: #64748b;
  font-size: 12px;
}

.project-overview-card strong {
  display: block;
  margin-top: 6px;
  color: #0f172a;
  font-size: 22px;
  line-height: 1;
}

.project-overview-card.tone-success {
  border-color: #bbf7d0;
  background: #f0fdf4;
}

.project-overview-card.tone-warning {
  border-color: #fde68a;
  background: #fffbeb;
}

.project-overview-card.tone-danger {
  border-color: #fecaca;
  background: #fef2f2;
}

.project-overview-card.tone-muted {
  border-color: #e2e8f0;
  background: #f8fafc;
}

.project-filter-bar {
  display: grid;
  grid-template-columns: minmax(260px, 1.4fr) 150px 150px max-content;
  gap: 10px;
  margin-bottom: 12px;
  align-items: center;
}

.project-search-input {
  min-width: 0;
}

.env-config {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 14px 46px;
  background: #f8fafc;
}

.env-config-card {
  padding: 14px;
  border: 1px solid #e1e8f2;
  border-radius: 8px;
  background: #ffffff;
}

.project-diagnostic-card {
  grid-column: 1 / -1;
  padding: 14px;
  border: 1px solid #d7e5ff;
  border-radius: 8px;
  background: #ffffff;
}

.env-config-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

dl {
  display: grid;
  grid-template-columns: 100px minmax(0, 1fr);
  gap: 8px 12px;
  margin: 0;
  color: #596578;
  font-size: 13px;
}

dt {
  color: #7b8798;
}

dd {
  margin: 0;
  word-break: break-word;
}

.status-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.readiness-cell {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.readiness-cell small {
  color: #64748b;
  font-size: 12px;
  line-height: 1.45;
}

.project-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.diagnostic-message {
  margin-left: 8px;
  color: #596578;
  font-size: 12px;
}

.latest-release {
  display: grid;
  gap: 6px;
}

.latest-release-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.latest-release small {
  color: #7b8798;
}

.webhook-hook-list {
  display: grid;
  gap: 6px;
}

.webhook-hook-item {
  display: grid;
  gap: 3px;
}

.webhook-hook-item small {
  color: #7b8798;
}

.run-link {
  color: #2563eb;
  text-decoration: none;
}

.run-link:hover {
  text-decoration: underline;
}

@media (max-width: 1080px) {
  .project-overview-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .project-filter-bar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .project-overview-grid,
  .project-filter-bar {
    grid-template-columns: 1fr;
  }

  .env-config {
    grid-template-columns: 1fr;
    padding: 12px;
  }
}
</style>
