// SPEC: PJ2026-010404 项目管理 draft-2026-06-25-p0-project-management-mdtodo; draft-2026-06-26-p1-mdtodo-web-operable.
// Responsibility: Cloud Web client for the public project-management same-origin API.

import { fetchJson } from "./client";
import type { ApiResult } from "@/types";

export interface ProjectManagementEnvelope {
  contractVersion?: string;
  serviceId?: string;
  ok?: boolean;
  valuesRedacted?: boolean;
}

export interface ProjectNavigationItem {
  id: string;
  label: string;
  apiRoute?: string;
}

export interface ProjectNavigationCapabilities {
  mdtodoProjection?: boolean;
  workbenchLaunch?: boolean;
  workbenchLinks?: boolean;
  sourceOfTruth?: string;
  [key: string]: unknown;
}

export interface ProjectNavigation {
  id: string;
  label: string;
  actor?: { id?: string | null; role?: string | null; authMethod?: string | null } | null;
  items?: ProjectNavigationItem[];
  capabilities?: ProjectNavigationCapabilities;
}

export interface ProjectProjectionSummary {
  sourceId?: string;
  documentCount?: number;
  taskCount?: number;
  projectedAt?: string;
  startedAt?: string;
}

export interface ProjectNavigationResponse extends ProjectManagementEnvelope {
  navigation?: ProjectNavigation;
  projection?: ProjectProjectionSummary | null;
}

export interface ProjectRecord {
  projectId: string;
  name?: string;
  title?: string;
  sourceIds?: string[];
  sourceOfTruth?: string;
  status?: string;
}

export interface ProjectSource {
  sourceId: string;
  kind?: string;
  sourceKind?: string;
  displayName?: string;
  projectId?: string;
  status?: string;
  hwpodId?: string | null;
  nodeId?: string | null;
  workspaceRootRef?: string | null;
  mdtodoRootRef?: string | null;
  maxFiles?: number;
  updatedAt?: string;
  valuesRedacted?: boolean;
}

export interface ProjectSourceInput {
  sourceId?: string;
  sourceKind?: string;
  displayName?: string;
  projectId?: string;
  hwpodId?: string;
  nodeId?: string;
  workspaceRootRef?: string;
  mdtodoRootRef?: string;
  maxFiles?: number;
}

export interface MdtodoFileRecord {
  sourceId: string;
  fileRef: string;
  projectId?: string;
  relativePath?: string;
  title?: string;
  fingerprint?: string;
  taskCount?: number;
  parseError?: string | null;
  revision?: number;
  lastIndexedAt?: string;
  updatedAt?: string;
}

export type MdtodoTaskStatus = "open" | "in_progress" | "completed";

export interface MdtodoTaskRecord {
  taskRef: string;
  projectId?: string;
  sourceId?: string;
  fileRef?: string;
  taskId?: string;
  rxxId?: string;
  title?: string;
  status?: MdtodoTaskStatus;
  parentTaskRef?: string | null;
  depth?: number;
  lineNumber?: number;
  ordinal?: number;
  linkCount?: number;
  sourceFingerprint?: string;
  bodyPreview?: string;
  parserMode?: string;
  links?: MdtodoTaskLinkRecord[];
  task?: {
    bodyPreview?: string | null;
    links?: MdtodoTaskLinkRecord[];
    linkCount?: number | null;
    title?: string | null;
    [key: string]: unknown;
  };
  updatedAt?: string;
}

export interface MdtodoTaskLinkRecord {
  linkId: string;
  label?: string;
  href?: string;
  kind?: string;
  relativePath?: string | null;
  ordinal?: number;
  availability?: string;
  message?: string;
  valuesRedacted?: boolean;
}

export interface MdtodoTaskDetailRecord {
  taskRef: string;
  taskId?: string;
  rxxId?: string;
  projectId?: string;
  sourceId?: string;
  fileRef?: string;
  relativePath?: string;
  title?: string;
  status?: MdtodoTaskStatus;
  lineNumber?: number;
  headingLevel?: number;
  statusMarker?: string | null;
  body?: string;
  bodyPreview?: string;
  links?: MdtodoTaskLinkRecord[];
  valuesRedacted?: boolean;
}

export interface MdtodoTaskDetailAuthority {
  state: "ready" | "unavailable";
  authority: "source-markdown" | "project-management-projection";
  sourceKind?: string | null;
  code?: string | null;
  message?: string | null;
  retryable?: boolean;
  valuesRedacted?: boolean;
}

export interface MdtodoExecutionContext {
  sourceId?: string | null;
  sourceKind?: string | null;
  projectId?: string | null;
  taskRef?: string | null;
  fileRef?: string | null;
  relativePath?: string | null;
  taskId?: string | null;
  hwpodId?: string | null;
  nodeId?: string | null;
  workspaceRootRef?: string | null;
  workspaceRootHash?: string | null;
  workspaceRootLabel?: string | null;
  mdtodoRootRef?: string | null;
  hwpodWorkspaceArgs?: string | null;
  contextFingerprint?: string | null;
  capabilities?: Record<string, unknown>;
  valuesRedacted?: boolean;
}

export interface MdtodoReportPreviewRecord {
  sourceId?: string;
  relativePath?: string;
  content?: string;
  fingerprint?: string;
  revision?: string;
  byteCount?: number;
  render?: string;
  linkId?: string;
  label?: string;
  href?: string;
  valuesRedacted?: boolean;
}

export interface ProjectWorkbenchLinkRecord {
  linkId: string;
  projectId?: string;
  taskRef?: string | null;
  sessionId?: string | null;
  traceId?: string | null;
  createdBy?: string | null;
  role?: string;
  createdAt?: string;
  updatedAt?: string;
  link?: {
    workbenchUrl?: string | null;
    launchContext?: {
      projectId?: string | null;
      taskRef?: string | null;
      sourceId?: string | null;
      fileRef?: string | null;
      taskId?: string | null;
      title?: string | null;
      valuesRedacted?: boolean;
    } | null;
    valuesRedacted?: boolean;
  } | null;
}

export interface ProjectListResponse extends ProjectManagementEnvelope { projects?: ProjectRecord[] }
export interface ProjectSourceListResponse extends ProjectManagementEnvelope { sources?: ProjectSource[] }
export interface ProjectSourceMutationResponse extends ProjectManagementEnvelope { source?: ProjectSource }
export interface ProjectSourceProbeResponse extends ProjectManagementEnvelope { probe?: { ok?: boolean; status?: string; sourceId?: string; sourceKind?: string; entries?: number; valuesRedacted?: boolean } }
export interface ProjectSourceReindexResponse extends ProjectManagementEnvelope { projection?: ProjectProjectionSummary & { sourceKind?: string; rootRef?: string; valuesRedacted?: boolean } }
export interface MdtodoFileListResponse extends ProjectManagementEnvelope { files?: MdtodoFileRecord[] }
export interface MdtodoTaskPage {
  offset?: number;
  limit?: number;
  maxLimit?: number;
  total?: number;
  hasMore?: boolean;
}
export interface MdtodoTaskListResponse extends ProjectManagementEnvelope { tasks?: MdtodoTaskRecord[]; page?: MdtodoTaskPage }
export interface MdtodoTaskDetailResponse extends ProjectManagementEnvelope {
  status?: "ready" | "partial";
  task?: MdtodoTaskRecord;
  detail?: MdtodoTaskDetailRecord | null;
  file?: MdtodoFileRecord;
  detailAuthority?: MdtodoTaskDetailAuthority;
}
export interface MdtodoLaunchContextResponse extends ProjectManagementEnvelope { task?: MdtodoTaskRecord; source?: Partial<ProjectSource>; executionContext?: MdtodoExecutionContext; launchContext?: Record<string, unknown> }
export interface MdtodoReportPreviewResponse extends ProjectManagementEnvelope { task?: MdtodoTaskRecord; link?: MdtodoTaskLinkRecord; report?: MdtodoReportPreviewRecord; file?: MdtodoFileRecord }
export interface MdtodoTaskMutationInput {
  sourceId?: string;
  fileRef?: string;
  parentTaskRef?: string;
  afterTaskRef?: string;
  expectedFingerprint?: string;
  revision?: string;
  title?: string;
  status?: MdtodoTaskStatus;
  body?: string;
}
export interface MdtodoTaskMutationResponse extends ProjectManagementEnvelope {
  task?: MdtodoTaskRecord | null;
  changedTaskId?: string | null;
  affectedTaskIds?: string[];
  file?: MdtodoFileRecord & { parserMode?: string; valuesRedacted?: boolean };
  projection?: ProjectProjectionSummary;
}
export interface ProjectWorkbenchLinkListResponse extends ProjectManagementEnvelope { links?: ProjectWorkbenchLinkRecord[] }

export interface MdtodoTaskQuery {
  taskRef?: string | null;
  sourceId?: string | null;
  fileRef?: string | null;
  projectId?: string | null;
  parentTaskRef?: string | null;
  status?: MdtodoTaskStatus | null;
  search?: string | null;
  limit?: number | null;
  offset?: number | null;
}

export interface ProjectWorkbenchLinkQuery {
  taskRef?: string | null;
  projectId?: string | null;
  sessionId?: string | null;
}

export const projectManagementAPI = {
  navigation: (): Promise<ApiResult<ProjectNavigationResponse>> => fetchJson("/v1/project-management/navigation", { timeoutMs: 12000, timeoutName: "project navigation" }),
  projects: (): Promise<ApiResult<ProjectListResponse>> => fetchJson("/v1/project-management/projects", { timeoutMs: 12000, timeoutName: "project list" }),
  sources: (): Promise<ApiResult<ProjectSourceListResponse>> => fetchJson("/v1/project-management/mdtodo/sources", { timeoutMs: 12000, timeoutName: "project mdtodo sources" }),
  createSource: (input: ProjectSourceInput): Promise<ApiResult<ProjectSourceMutationResponse>> => fetchJson("/v1/project-management/mdtodo/sources", { method: "POST", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo source create" }),
  updateSource: (sourceId: string, input: ProjectSourceInput): Promise<ApiResult<ProjectSourceMutationResponse>> => fetchJson(`/v1/project-management/mdtodo/sources/${encodeURIComponent(sourceId)}`, { method: "PATCH", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo source update" }),
  probeSource: (sourceId: string): Promise<ApiResult<ProjectSourceProbeResponse>> => fetchJson(`/v1/project-management/mdtodo/sources/${encodeURIComponent(sourceId)}/probe`, { method: "POST", body: JSON.stringify({}), timeoutMs: 12000, timeoutName: "project mdtodo source probe" }),
  reindexSource: (sourceId: string): Promise<ApiResult<ProjectSourceReindexResponse>> => fetchJson(`/v1/project-management/mdtodo/sources/${encodeURIComponent(sourceId)}/reindex`, { method: "POST", body: JSON.stringify({}), timeoutMs: 12000, timeoutName: "project mdtodo source reindex" }),
  files: (sourceId?: string | null): Promise<ApiResult<MdtodoFileListResponse>> => fetchJson(`/v1/project-management/mdtodo/files${queryString({ sourceId })}`, { timeoutMs: 12000, timeoutName: "project mdtodo files" }),
  tasks: (query: MdtodoTaskQuery = {}): Promise<ApiResult<MdtodoTaskListResponse>> => fetchJson(`/v1/project-management/mdtodo/tasks${queryString({ taskRef: query.taskRef, sourceId: query.sourceId, fileRef: query.fileRef, projectId: query.projectId, parentTaskRef: query.parentTaskRef, status: query.status, search: query.search, limit: query.limit, offset: query.offset })}`, { timeoutMs: 12000, timeoutName: "project mdtodo tasks" }),
  taskDetail: (taskRef: string): Promise<ApiResult<MdtodoTaskDetailResponse>> => fetchJson(`/v1/project-management/mdtodo/task-detail${queryString({ taskRef })}`, { timeoutMs: 12000, timeoutName: "project mdtodo task detail" }),
  launchContext: (taskRef: string): Promise<ApiResult<MdtodoLaunchContextResponse>> => fetchJson(`/v1/project-management/mdtodo/launch-context${queryString({ taskRef })}`, { timeoutMs: 12000, timeoutName: "project mdtodo launch context" }),
  reportPreview: (taskRef: string, linkId: string): Promise<ApiResult<MdtodoReportPreviewResponse>> => fetchJson(`/v1/project-management/mdtodo/report-preview${queryString({ taskRef, linkId })}`, { timeoutMs: 12000, timeoutName: "project mdtodo report preview" }),
  updateTask: (taskRef: string, input: MdtodoTaskMutationInput): Promise<ApiResult<MdtodoTaskMutationResponse>> => fetchJson(`/v1/project-management/mdtodo/tasks/${encodeURIComponent(taskRef)}`, { method: "PATCH", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo task update" }),
  createTask: (input: MdtodoTaskMutationInput): Promise<ApiResult<MdtodoTaskMutationResponse>> => fetchJson("/v1/project-management/mdtodo/tasks", { method: "POST", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo task create" }),
  deleteTask: (taskRef: string, input: MdtodoTaskMutationInput): Promise<ApiResult<MdtodoTaskMutationResponse>> => fetchJson(`/v1/project-management/mdtodo/tasks/${encodeURIComponent(taskRef)}`, { method: "DELETE", body: JSON.stringify(input), timeoutMs: 12000, timeoutName: "project mdtodo task delete" }),
  workbenchLinks: (query: ProjectWorkbenchLinkQuery = {}): Promise<ApiResult<ProjectWorkbenchLinkListResponse>> => fetchJson(`/v1/project-management/workbench-links${queryString({ taskRef: query.taskRef, projectId: query.projectId, sessionId: query.sessionId })}`, { timeoutMs: 12000, timeoutName: "project workbench links" })
};

function queryString(values: Record<string, string | number | null | undefined>): string {
  const params = new URLSearchParams();
  for (const [key, value] of Object.entries(values)) {
    if (value !== null && value !== undefined && value !== "") params.set(key, String(value));
  }
  const text = params.toString();
  return text ? `?${text}` : "";
}
