<!-- SPEC: MDTODO 三栏任务工作区. -->
<!-- Implementation reference: MDTODO R2 / PJ2026-010405 云端控制台. -->
<script setup lang="ts">
import { computed, reactive } from "vue";
import ApiErrorDiagnostic from "@/components/common/ApiErrorDiagnostic.vue";
import EmptyState from "@/components/common/EmptyState.vue";
import LoadingState from "@/components/common/LoadingState.vue";
import SplitWorkspaceLayout from "@/components/layout/SplitWorkspaceLayout.vue";
import StatusStrip, {
  type ConsoleStatusItem,
} from "@/components/layout/StatusStrip.vue";
import MdtodoCreateTaskDialog from "@/components/mdtodo/MdtodoCreateTaskDialog.vue";
import MdtodoInfoDialog from "@/components/mdtodo/MdtodoInfoDialog.vue";
import MdtodoReportPanel from "@/components/mdtodo/MdtodoReportPanel.vue";
import MdtodoSourceDialog from "@/components/mdtodo/MdtodoSourceDialog.vue";
import MdtodoTaskPanel from "@/components/mdtodo/MdtodoTaskPanel.vue";
import MdtodoTaskTree from "@/components/mdtodo/MdtodoTaskTree.vue";
import MdtodoToolbar from "@/components/mdtodo/MdtodoToolbar.vue";
import { useMdtodoWorkspaceController } from "@/composables/mdtodo/useMdtodoWorkspaceController";

const model = reactive(useMdtodoWorkspaceController());
const statusItems = computed<ConsoleStatusItem[]>(() => [
  {
    id: "source",
    label: "Source",
    value: model.selectedSource?.displayName || model.selectedSourceId || "未选择",
    tone: model.selectedSourceId ? "ok" : "warn",
  },
  {
    id: "file",
    label: "File",
    value: model.selectedFileName || "未选择",
    tone: model.selectedFileRef ? "info" : "warn",
  },
  {
    id: "tasks",
    label: "Tasks",
    value: model.fileTasks.length,
    detail: `${model.filteredTasks.length} 个任务符合当前筛选`,
  },
  {
    id: "authority",
    label: "Authority",
    value: model.taskDetailPartial ? "离线投影只读" : "Source Markdown",
    tone: model.taskDetailPartial ? "warn" : "ok",
  },
  {
    id: "report",
    label: "Report",
    value: model.reportOpen ? "open" : "closed",
    tone: model.reportOpen ? "info" : "neutral",
  },
]);
</script>

<template>
  <section
    class="mdtodo-page"
    data-testid="project-management-mdtodo"
    :data-view="model.viewState.view"
  >
    <h1 class="sr-only">MDTODO</h1>
    <LoadingState
      v-if="model.loading && !model.source.sources.length"
      label="加载 MDTODO source"
    />
    <EmptyState
      v-else-if="model.error && !model.source.sources.length"
      title="MDTODO 加载失败"
      :description="model.error"
      :api-error="model.apiError"
      :diagnostic="model.diagnostic"
      action-label="重试"
      @action="model.loadPage"
    />
    <template v-else>
      <MdtodoToolbar
        :sources="model.source.sources"
        :source-id="model.selectedSourceId"
        :files="model.taskData.files"
        :file-ref="model.selectedFileRef"
        :view="model.viewState.view"
        :busy="model.taskData.taskLoading || model.source.sourceReindexLoading"
        :create-disabled="model.createDisabled"
        :create-disabled-reason="model.createDisabledReason"
        :reindex-disabled="!model.selectedSourceId"
        @select-source="model.selectSource"
        @select-file="model.selectFile"
        @select-view="model.viewState.update({ view: $event })"
        @create="
          model.createDisabled ? undefined : (model.showTaskCreate = true)
        "
        @configure="model.openSourceConfig"
        @reindex="model.reindex"
        @info="model.showInfo = true"
      />
      <StatusStrip :items="statusItems" label="MDTODO 当前上下文" live="polite" />
      <nav class="mobile-tabs" role="tablist" aria-label="MDTODO 面板">
        <button
          role="tab"
          type="button"
          :aria-selected="model.viewState.tab === 'tasks'"
          @click="model.viewState.update({ tab: 'tasks' })"
        >
          任务
        </button>
        <button
          role="tab"
          type="button"
          :aria-selected="model.viewState.tab === 'document'"
          @click="model.viewState.update({ tab: 'document' })"
        >
          正文
        </button>
        <button
          role="tab"
          type="button"
          :disabled="!model.reportOpen"
          :aria-selected="model.viewState.tab === 'report'"
          @click="model.viewState.update({ tab: 'report' })"
        >
          报告
        </button>
      </nav>
      <div
        v-if="
          model.error || model.source.sourceMessage || model.source.sourceError
        "
        class="page-notice"
        :data-error="Boolean(model.error || model.source.sourceError)"
      >
        <div class="page-notice-summary">
          <span>{{
            model.error ||
            model.source.sourceError ||
            model.source.sourceMessage
          }}</span>
          <button v-if="model.error" type="button" @click="model.reloadWindow">
            重试
          </button>
        </div>
        <ApiErrorDiagnostic
          v-if="model.error && (model.apiError || model.diagnostic)"
          title="请求诊断"
          :error="model.error"
          :api-error="model.apiError"
          :diagnostic="model.diagnostic"
          :show-message="false"
          compact
        />
      </div>
      <div class="pane-controls">
        <button
          type="button"
          :data-testid="
            model.taskPaneCollapsed
              ? 'mdtodo-expand-left'
              : 'mdtodo-collapse-left'
          "
          :aria-label="
            model.taskPaneCollapsed ? '展开任务索引' : '折叠任务索引'
          "
          @click="model.taskPaneCollapsed = !model.taskPaneCollapsed"
        >
          {{ model.taskPaneCollapsed ? "展开任务" : "折叠任务" }}
        </button>
        <span />
        <button
          v-if="model.reportOpen"
          type="button"
          :data-testid="
            model.reportPaneCollapsed
              ? 'mdtodo-expand-right'
              : 'mdtodo-collapse-right'
          "
          :aria-label="model.reportPaneCollapsed ? '展开报告' : '折叠报告'"
          @click="model.reportPaneCollapsed = !model.reportPaneCollapsed"
        >
          {{ model.reportPaneCollapsed ? "展开报告" : "折叠报告" }}
        </button>
      </div>
      <SplitWorkspaceLayout
        :left-width="
          model.viewState.view === 'queue'
            ? model.queuePaneWidth
            : model.taskPaneWidth
        "
        @update:left-width="
          model.viewState.view === 'queue'
            ? (model.queuePaneWidth = $event)
            : (model.taskPaneWidth = $event)
        "
        v-model:right-width="model.reportPaneWidth"
        class="mdtodo-workspace"
        :class="`mobile-${model.viewState.tab}`"
        :left-collapsed="model.taskPaneCollapsed"
        :right-open="model.reportOpen"
        :right-collapsed="model.reportPaneCollapsed"
        :min-left-width="20"
        :max-left-width="model.viewState.view === 'queue' ? 48 : 32"
        :min-right-width="35"
        :max-right-width="62"
        left-resizer-test-id="mdtodo-task-pane-resizer"
        right-resizer-test-id="mdtodo-report-pane-resizer"
      >
        <template #left>
          <MdtodoTaskTree
            :tasks="model.filteredTasks"
            :selected-task-ref="model.selectedTaskRef"
            :collapsed-task-refs="model.collapsedTaskRefs"
            :search="model.taskSearch"
            :status="model.taskStatus"
            :page="model.taskData.taskPage"
            :loading="model.taskData.taskLoading"
            :file-scoped-task-count="model.fileTasks.length"
            @select="model.selectTask"
            @update:collapsed-task-refs="model.collapsedTaskRefs = $event"
            @update-search="model.taskSearch = $event"
            @update-status="model.taskStatus = $event"
            @load-more="model.loadMore"
          />
        </template>
        <MdtodoTaskPanel
          :task="model.selectedTask"
          :detail="model.currentTaskDetail"
          :detail-loading="model.taskData.taskDetailLoading"
          :detail-error="model.taskData.taskDetailError"
          :detail-partial="model.taskDetailPartial"
          :mutation-disabled="model.mutationDisabled"
          :links="model.selectedTaskLinks"
          :editing-title="model.editingTitle"
          :editing-body="model.editingBody"
          :edit-title="model.editTitle"
          :edit-status="model.editStatus"
          :edit-body="model.editBody"
          :delete-confirm="model.deleteConfirm"
          :mutation-loading="model.mutation.taskMutationLoading"
          :mutation-message="model.mutation.taskMutationMessage"
          :mutation-error="model.mutation.taskMutationError"
          :launch-loading="model.launch.launchLoading"
          :launch-error="model.launch.launchError"
          :launch-api-error="model.launch.launchApiError"
          :launch-diagnostic="model.launch.launchDiagnostic"
          :launch-enabled="!model.launchDisabled"
          :launch-blocker="model.launchBlocker"
          :provider-profile="model.providerProfile"
          :provider-options="model.providerOptions"
          @update:edit-title="model.editTitle = $event"
          @update:edit-status="model.editStatus = $event"
          @update:edit-body="model.editBody = $event"
          @update:provider-profile="model.setProvider"
          @begin-title-edit="model.editingTitle = true"
          @cancel-title-edit="model.resetEditor(model.selectedTask)"
          @save-task-basics="model.saveBasics"
          @begin-body-edit="model.editingBody = true"
          @cancel-body-edit="model.resetEditor(model.selectedTask)"
          @save-task-body="model.saveBody"
          @delete-task="model.deleteTask"
          @cancel-delete="model.deleteConfirm = false"
          @open-report="model.openReport"
          @launch-workbench="model.launchWorkbench"
        />
        <template #right>
          <MdtodoReportPanel
            :report="model.report.reportPreview"
            :active-link="model.report.activeReportLink"
            :loading="model.report.reportLoading"
            :error="model.report.reportError"
            :collapsed="model.reportPaneCollapsed"
            :show-fullscreen="model.report.showReportFullscreen"
            @update:collapsed="model.reportPaneCollapsed = $event"
            @close="model.closeReport"
            @open-fullscreen="model.report.openFullscreen()"
            @close-fullscreen="model.report.closeFullscreen()"
          />
        </template>
      </SplitWorkspaceLayout>
    </template>

    <MdtodoCreateTaskDialog
      :show="model.showTaskCreate"
      :new-title="model.newTaskTitle"
      :new-body="model.newTaskBody"
      :loading="model.mutation.taskMutationLoading"
      :disabled="model.createDisabled"
      :disabled-reason="model.createDisabledReason"
      :error="model.mutation.taskMutationError"
      :has-selected-task="Boolean(model.selectedTask)"
      @close="model.showTaskCreate = false"
      @update:new-title="model.newTaskTitle = $event"
      @update:new-body="model.newTaskBody = $event"
      @create="model.createTask"
    />
    <MdtodoSourceDialog
      :show="model.showSourceConfig"
      :form="model.source.sourceForm"
      :saving="model.source.sourceSaving"
      :probe-loading="model.source.sourceProbeLoading"
      :reindex-loading="model.source.sourceReindexLoading"
      :reindex-disabled="
        !model.source.sourceForm.sourceId ||
        model.source.sourceForm.sourceId !== model.selectedSourceId
      "
      :message="model.source.sourceMessage"
      :error="model.source.sourceError"
      @close="model.showSourceConfig = false"
      @save="model.saveSource"
      @probe="model.source.probeSource(model.source.sourceForm.sourceId)"
      @reindex="model.reindex"
    />
    <MdtodoInfoDialog
      :show="model.showInfo"
      :sources="model.source.sources"
      :selected-source="model.selectedSource"
      :selected-source-id="model.selectedSourceId"
      :selected-file="model.selectedFile"
      :selected-file-ref="model.selectedFileRef"
      :selected-file-name="model.selectedFileName"
      :selected-task="model.selectedTask"
      :links="model.taskData.links"
      :task-page="model.taskData.taskPage"
      :file-scoped-task-count="model.fileTasks.length"
      :task-status-counts="model.taskStatusCounts"
      :navigation="model.source.navigation"
      @close="model.showInfo = false"
    />
  </section>
</template>

<style scoped>
.mdtodo-page {
  display: grid;
  grid-template-rows: auto auto auto auto auto minmax(0, 1fr);
  min-width: 0;
  min-height: 0;
  height: calc(100dvh - 68px);
  overflow: hidden;
  border: 1px solid #b8c7ce;
  background: #e9f0f2;
}
.mdtodo-workspace {
  min-height: 0;
  height: 100%;
}
.mdtodo-page > :deep(.loading-state),
.mdtodo-page > :deep(.empty-state) {
  grid-row: 1 / -1;
  min-height: 0;
  height: 100%;
}
.page-notice {
  display: grid;
  gap: 5px;
  border-bottom: 1px solid #b9d7c3;
  background: #edf8f1;
  padding: 6px 10px;
  color: #286342;
  font-size: 12px;
}
.page-notice-summary {
  display: flex;
  min-width: 0;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.page-notice-summary span {
  min-width: 0;
  overflow-wrap: anywhere;
}
.page-notice[data-error="true"] {
  border-color: #e1b1aa;
  background: #fff1ef;
  color: #943d31;
}
.mobile-tabs {
  display: none;
}
.pane-controls {
  display: flex;
  align-items: center;
  gap: 6px;
  border-bottom: 1px solid #c4d0d6;
  background: #f4f7f8;
  padding: 4px 7px;
}
.pane-controls span {
  flex: 1;
}
.pane-controls button {
  height: 25px;
  border: 1px solid #a9bbc4;
  background: #fff;
  color: #355461;
  font-size: 10px;
  font-weight: 750;
}
@media (max-width: 640px) {
  .mdtodo-page {
    height: calc(100dvh - 58px);
    max-width: 100%;
  }
  .mobile-tabs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    border-bottom: 1px solid #b8c7ce;
  }
  .mobile-tabs button {
    height: 34px;
    border: 0;
    border-right: 1px solid #c3d0d6;
    background: #f5f8f9;
    color: #385663;
    font-size: 11px;
    font-weight: 750;
  }
  .mobile-tabs button[aria-selected="true"] {
    background: #dcecf2;
    color: #15536b;
  }
  .pane-controls {
    display: none;
  }
  .mdtodo-workspace {
    grid-template-columns: minmax(0, 1fr) !important;
    grid-template-rows: minmax(0, 1fr) !important;
    gap: 0 !important;
  }
  .mdtodo-workspace :deep(.split-workspace-left),
  .mdtodo-workspace :deep(.split-workspace-main),
  .mdtodo-workspace :deep(.split-workspace-right) {
    display: none;
  }
  .mdtodo-workspace.mobile-tasks :deep(.split-workspace-left),
  .mdtodo-workspace.mobile-document :deep(.split-workspace-main) {
    display: block;
    width: 100%;
    min-width: 0;
  }
  .mdtodo-workspace.mobile-report :deep(.split-workspace-right) {
    display: block;
    width: 100%;
    min-width: 0;
  }
  .mdtodo-workspace :deep([role="separator"]) {
    display: none;
  }
}
</style>
