import { T as u } from "../../shared-types-CIxCt9tj.js";
import { F as g } from "../../file-lock-D4f90hJ2.js";
function I(i) {
  const t = i.match(/^(\d+(?:\.\d+)*)\s/) || i.match(/^(\d+(?:\.\d+)*)\./);
  return t ? t[1] : null;
}
function d(i) {
  return i.split(".").length;
}
function f(i) {
  const t = i.match(/^(\s*)([-*+])\s+\[([ xX\-~])\](\\?\*?)\s+(.+)$/);
  if (!t)
    return { isTask: !1, indent: 0, status: u.NotStarted, text: "", taskNumber: null, isOptional: !1 };
  const s = t[3].toLowerCase(), e = t[4], o = e === "*" || e === "\\*";
  let n;
  s === "x" ? n = u.Completed : s === "-" ? n = u.InProgress : s === "~" ? n = u.Queued : n = u.NotStarted;
  const a = t[5];
  return { isTask: !0, indent: t[1].length, status: n, text: a, taskNumber: I(a), isOptional: o };
}
function m(i, t, s) {
  const e = f(i[t]);
  if (!e.isTask)
    throw new Error(`Invalid task format at line ${t}: ${i[t]}`);
  const o = {
    id: e.taskNumber ?? e.text,
    text: e.text,
    startLine: t,
    endLine: t + 1,
    markdownStatus: e.status,
    content: "",
    subTasks: [],
    level: s,
    isOptional: e.isOptional
  };
  let n = t + 1;
  const a = [];
  let c = -1;
  for (; n < i.length; ) {
    const r = i[n], k = f(r), l = r.match(/^(\s*)/)?.[1].length || 0;
    if (e.taskNumber) {
      if (k.isTask) break;
    } else {
      if (r.trim() !== "" && l <= e.indent) break;
      if (k.isTask) {
        const { task: h, nextIndex: x } = m(i, n, s + 1);
        o.subTasks.push(h), n = x;
        continue;
      }
    }
    if (r.trim() !== "") {
      const h = Math.min(l, e.indent + 2);
      a.push(r.substring(h)), c = a.length - 1;
    } else c !== -1 && a.push("");
    n++;
  }
  for (; a.length > 0 && a[a.length - 1] === ""; )
    a.pop();
  return a.length > 0 && (o.content = a.join(`
`)), o.endLine = n, { task: o, nextIndex: n };
}
function N(i) {
  const t = [], s = /* @__PURE__ */ new Map(), e = /* @__PURE__ */ new Set(), o = i.filter(
    (n) => n.taskInfo.taskNumber !== null
  );
  o.sort((n, a) => {
    const c = d(n.taskInfo.taskNumber), r = d(a.taskInfo.taskNumber);
    return c !== r ? c - r : n.taskInfo.taskNumber.localeCompare(a.taskInfo.taskNumber, void 0, { numeric: !0 });
  });
  for (const { task: n, taskInfo: a } of o) {
    const c = a.taskNumber, r = d(c);
    if (n.level = r, n.subTasks = [], s.set(c, n), r > 1) {
      const k = c.substring(0, c.lastIndexOf(".")), l = s.get(k);
      l ? l.subTasks.push(n) : e.add(c);
    }
  }
  for (const { task: n, taskInfo: a } of i)
    a.taskNumber !== null ? (d(a.taskNumber) === 1 || e.has(a.taskNumber)) && t.push(n) : t.push(n);
  return t;
}
function P(i) {
  const s = i.replace(/\r\n/g, `
`).replace(/\r/g, `
`).split(`
`);
  let e = 0;
  const o = [];
  for (; e < s.length; ) {
    const a = f(s[e]);
    if (a.isTask) {
      const { task: c, nextIndex: r } = m(s, e, 1);
      c.id = a.taskNumber ?? a.text, o.push({ task: c, lineIndex: e, taskInfo: a }), e = r;
    } else
      e++;
  }
  return o.some((a) => a.taskInfo.taskNumber !== null) ? N(o) : o.map(({ task: a }) => a);
}
const y = /(?:_|\*\*)Property(?:\s+\d+)?(?::\s*.+)?(?:_|\*\*)/i;
function T() {
  return { pbtResults: {}, executionHistory: {} };
}
function p(i) {
  return i.replace(/\.md$/, ".meta.json");
}
function S(i) {
  switch (i) {
    case u.Completed:
      return "x";
    case u.InProgress:
      return "-";
    case u.Queued:
      return "~";
    default:
      return " ";
  }
}
function b(i, t) {
  for (const s of i) {
    if (s.id === t) return s;
    if (s.subTasks.length > 0) {
      const e = b(s.subTasks, t);
      if (e) return e;
    }
  }
}
function w(i) {
  const t = [];
  for (const s of i.subTasks)
    !s.isOptional && s.markdownStatus !== u.Completed && t.push(s), t.push(...w(s));
  return t;
}
class M {
  constructor(t) {
    this.fs = t;
  }
  async loadMetadata(t) {
    const s = p(t);
    try {
      if (!await this.fs.exists(s)) return T();
      const { content: o } = await this.fs.readTextFile({ path: s });
      return JSON.parse(o);
    } catch {
      return T();
    }
  }
  async saveMetadata(t, s) {
    const e = p(t);
    await this.fs.writeTextFile({ path: e, content: JSON.stringify(s, null, 2) });
  }
  async readAndParseTasks(t) {
    const { content: s } = await this.fs.readTextFile({ path: t });
    return { content: s, tasks: P(s) };
  }
  async resolveTask(t, s) {
    const { tasks: e } = await this.readAndParseTasks(t), o = b(e, s);
    if (!o)
      throw new Error(`Task "${s}" not found in ${t}`);
    return { task: o, tasks: e };
  }
  /** Writes the new checkbox status into the markdown task file. */
  async updateTaskStatus(t) {
    const s = t.tasksPath.fsPath, e = t.status;
    await g.getInstance().withLock(t.tasksPath, async () => {
      const { task: a } = await this.resolveTask(s, t.taskId), { content: c } = await this.fs.readTextFile({ path: s }), r = c.replace(/\r\n/g, `
`).split(`
`), k = r[a.startLine].replace(/\[([ xX\-~])\]/, `[${S(e)}]`);
      r[a.startLine] = k, await this.fs.writeTextFile({ path: s, content: r.join(`
`) });
    });
    const o = await this.loadMetadata(s), n = o.executionHistory[t.taskId] ?? [];
    n.push({
      executionId: t.executionId,
      chatSessionId: t.chatSessionId,
      timestamp: Date.now()
    }), o.executionHistory[t.taskId] = n, await this.saveMetadata(s, o);
  }
  /** Checks hierarchy and ordering rules before allowing a status transition. */
  async validateTaskStatusChange(t) {
    const s = t.newStatus;
    let e, o;
    try {
      const a = await this.resolveTask(t.tasksPath.fsPath, t.taskId);
      e = a.task, o = a.tasks;
    } catch {
      return { valid: !1, reason: `Task "${t.taskId}" not found` };
    }
    if (s === u.Completed) {
      const a = w(e);
      if (a.length > 0)
        return { valid: !1, reason: `Cannot complete task with incomplete non-optional subtasks: ${a.map((r) => `"${r.text}"`).join(", ")}` };
    }
    const n = [];
    return s === u.InProgress && n.push(...this.checkTaskOrder(o, e)), { valid: !0, warnings: n.length > 0 ? n : void 0 };
  }
  /** Returns whether the task is a leaf (has no subtasks). */
  async getTaskMetadata(t) {
    const { task: s } = await this.resolveTask(t.tasksPath.fsPath, t.taskId);
    return { isLeaf: s.subTasks.length === 0 };
  }
  /** Validates the task is a PBT task and persists the test result. */
  async updatePBTStatus(t) {
    const s = t.tasksPath.fsPath, { task: e } = await this.resolveTask(s, t.taskId);
    if (!y.test(e.content))
      throw new Error(`Task "${t.taskId}" is not a PBT task`);
    const o = await this.loadMetadata(s);
    o.pbtResults[t.taskId] = {
      status: t.status,
      failingExample: t.failingExample,
      lastRunTimestamp: Date.now()
    }, await this.saveMetadata(s, o);
  }
  /** Looks up a task by ID and returns its text and line range. */
  async getTask(t) {
    try {
      const { task: s } = await this.resolveTask(t.tasksPath.fsPath, t.taskId);
      return { text: s.text, startLine: s.startLine, endLine: s.endLine };
    } catch {
      return null;
    }
  }
  /**
   * Warns when starting a task while earlier siblings are incomplete.
   */
  checkTaskOrder(t, s) {
    const e = [], o = this.findSiblings(t, s);
    for (const n of o) {
      if (n.id === s.id) break;
      n.markdownStatus !== u.Completed && !n.isOptional && e.push(`Task "${n.text}" has not been completed yet and appears before this task.`);
    }
    return e;
  }
  findSiblings(t, s) {
    for (const e of t) {
      if (e.id === s.id) return t;
      if (e.subTasks.length > 0) {
        const o = this.findSiblings(e.subTasks, s);
        if (o.length > 0) return o;
      }
    }
    return [];
  }
}
export {
  M as NodeTaskService,
  P as parseMarkdownTasks
};
//# sourceMappingURL=index.js.map
