#!/usr/bin/env bash
# PR #29953 (fix(shared): open file links that include a line range)
# Claim: already-fixed. #34006 (merged, cited by the maintainer who closed issue #28555) taught the shared
# file-link parser `:67-69`: relative/bare ranges become links, absolute ranges open the real file at
# the start line, and the chip reads L67-69. Behavioral proof: the PR's own new shared/mobile test rows
# and a focused test of every case the PR says fails on main pass on current main and fail before #34006.
# Needs deps installed (`vp i`) and `gh` authenticated. Run from the root of a clean t3code checkout.
set -euo pipefail

REPO=pingdotgg/t3code
ok=1
pass() { echo "PASS  $*"; }
fail() { echo "FAIL  $*"; ok=0; }

if [ -n "$(git status --porcelain)" ]; then
  echo "refusing to run on a dirty tree"; exit 2
fi
ORIG=$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)
WORK=$(mktemp -d)
TEST=apps/web/src/fileLinkRanges29953.logic.test.ts
cleanup() {
  rm -f "$TEST"
  git checkout -q -f -- . 2>/dev/null || true
  git checkout -q -f "$ORIG"
  rm -rf "$WORK"
}
trap 'rc=$?; cleanup; [ "${PROOF_DONE:-0}" = 1 ] && exit 0; [ "$rc" -ne 0 ] && exit "$rc"; exit 1' EXIT

git fetch -q origin main

MAIN=$(git rev-parse FETCH_HEAD)
git fetch -q origin pull/29953/head
PR_HEAD=$(git rev-parse FETCH_HEAD)
MB=$(git merge-base "$MAIN" "$PR_HEAD")
echo "main=$MAIN pr_head=$PR_HEAD merge_base=$MB"

# 1. The superseding PR is on main and the maintainer closed the linked issue citing it.
FIX=$(git log "$MAIN" --format=%H --grep="(#34006)" | head -1)
if [ -n "$FIX" ]; then pass "#34006 is on main as ${FIX:0:10} ($(git log -1 --format=%s "$FIX"))"
else fail "#34006 not found on main"; FIX=$MAIN; fi
issue=$(gh api graphql -f query='query{repository(owner:"pingdotgg",name:"t3code"){issue(number:28555){state stateReason timelineItems(itemTypes:[CLOSED_EVENT],last:1){nodes{... on ClosedEvent{actor{login}}}}}}}' \
  --jq '.data.repository.issue | "\(.state) \(.stateReason) \(.timelineItems.nodes[0].actor.login)"')
cited=$(gh api "repos/$REPO/issues/28555/comments" --jq '[.[] | select(.user.login == "juliusmarminge") | .body] | last')
if [ "$issue" = "CLOSED COMPLETED juliusmarminge" ] && grep -q "34006" <<<"$cited"; then
  pass "issue #28555 closed as completed by juliusmarminge, citing #34006"
else
  fail "issue #28555 state/closer is '$issue'"
fi

# 2. The PR's own new shared and mobile test rows pass on main without its source changes.
git diff "$MB" "$PR_HEAD" -- packages/shared/src/markdownLinks.test.ts \
  apps/mobile/src/lib/markdownInlineFileLinks.test.ts > "$WORK/tests.diff"
git checkout -q --detach "$MAIN"
git apply "$WORK/tests.diff"
vp test run packages/shared/src/markdownLinks.test.ts apps/mobile/src/lib/markdownInlineFileLinks.test.ts \
  > "$WORK/own.log" 2>&1 || true
grep -E "Tests +[0-9]" "$WORK/own.log" || true
if grep -qE "Tests +[0-9]+ passed" "$WORK/own.log" && ! grep -qE "Tests +.*[0-9]+ failed" "$WORK/own.log"; then
  pass "the PR's added range rows in markdownLinks.test.ts and markdownInlineFileLinks.test.ts pass on main"
else
  fail "the PR's own range rows fail on main"
fi
git checkout -q -f -- .

# 3. Every case the PR lists as failing on main, as a focused test.
write_test() {
cat > "$TEST" <<'TS'
// Proof for PR #29953: the line-range cases its description says fail on main, run against main.
import { fileLinkLabel, formatFilePathPosition, splitFilePathPosition } from "@t3tools/shared/fileLinks";
import {
  inlineCodeFilePathCandidate,
  parseMarkdownFileLink,
  resolveMarkdownFileLinkTarget,
} from "@t3tools/shared/markdownLinks";
import { describe, expect, it } from "vite-plus/test";

import { resolveInlineCodeFileLinkMeta, resolveMarkdownFileLinkMeta } from "./markdown-links";
import { markdownFileEditorTarget, resolveMarkdownFileHostPath } from "./markdownFileHostPath";

describe("PR #29953 claims on main", () => {
  it("reads :67-69 as a start and end line", () => {
    expect(splitFilePathPosition("src/main.ts:67-69")).toMatchObject({
      path: "src/main.ts",
      line: 67,
      endLine: 69,
    });
    expect(splitFilePathPosition(String.raw`C:\repo\foo.py:67-69`)).toMatchObject({
      path: String.raw`C:\repo\foo.py`,
      line: 67,
      endLine: 69,
    });
  });

  it("links relative and bare-name ranges written as inline code", () => {
    expect(inlineCodeFilePathCandidate("src/foo.py:67-69")).toBe("src/foo.py:67-69");
    expect(inlineCodeFilePathCandidate("foo.py:1-3")).toBe("foo.py:1-3");
    expect(resolveInlineCodeFileLinkMeta("src/foo.py:67-69", "/repo")).toMatchObject({
      filePath: "/repo/src/foo.py",
      line: 67,
      endLine: 69,
    });
  });

  it("parses a range in a Markdown link and resolves it to its start line", () => {
    expect(parseMarkdownFileLink("src/foo.py:67-69")).toEqual({
      path: "src/foo.py",
      line: 67,
      endLine: 69,
    });
    expect(resolveMarkdownFileLinkTarget("script.ts:67-69", "/Users/julius/project")).toBe(
      "/Users/julius/project/script.ts:67",
    );
  });

  it("labels the chip with the range", () => {
    expect(fileLinkLabel({ path: "/tmp/locomo.py", line: 67, endLine: 69 }, new Map())).toBe(
      "locomo.py · L67–69",
    );
  });

  it("opens an absolute range at the existing file's first line, never a ':67-69' filename", async () => {
    const meta = resolveMarkdownFileLinkMeta("/abs/path/foo.py:67-69", "/abs/path");
    if (!meta) throw new Error("Expected a file link");
    expect(meta).toMatchObject({ filePath: "/abs/path/foo.py", line: 67, endLine: 69 });
    const hostPath = await resolveMarkdownFileHostPath({
      meta,
      cwd: "/abs/path",
      findWorkspaceMatch: async () => null,
    });
    // The editor target the client sends to the server's launcher carries the start line only.
    expect(markdownFileEditorTarget(meta, hostPath)).toBe("/abs/path/foo.py:67");
    expect(formatFilePathPosition({ path: "/abs/path/foo.py", line: 67, endLine: 69 })).toBe(
      "/abs/path/foo.py:67",
    );
  });
});
TS
}
write_test
vp test run --reporter=verbose "$TEST" > "$WORK/main.log" 2>&1 || true
grep -E "^ +(✓|×)|Tests +[0-9]" "$WORK/main.log" || true
if grep -qE "Tests +5 passed" "$WORK/main.log" && ! grep -qE "Tests +.*[0-9]+ failed" "$WORK/main.log"; then
  pass "all 5 range cases pass on main ($MAIN)"
else
  fail "a range case fails on main"
fi
rm -f "$TEST"

# 4. The same cases fail on main just before #34006, so they capture the reported bug.
git checkout -q --detach "$FIX^1"
write_test
vp test run --reporter=verbose "$TEST" > "$WORK/before.log" 2>&1 || true
grep -E "^ +(✓|×)|AssertionError|Tests +[0-9]" "$WORK/before.log" || true
if grep -qE "Tests +5 failed" "$WORK/before.log"; then
  pass "all 5 range cases fail on $(git rev-parse --short HEAD), the commit before #34006"
else
  fail "the range cases did not fail before #34006"
fi
rm -f "$TEST"

# What the PR still changes: the server launcher also accepts a `file:67-69` target. No client on
# main sends one (check 3 shows the editor target is `file:67`), so this is not a user-visible gap.
echo "INFO  remaining PR diff vs main: $(git diff --name-only "$MB" "$PR_HEAD" | tr '\n' ' ')"

if [ "$ok" = 1 ]; then
  echo "VERDICT: CLOSE (already-fixed) - #34006 already links and opens file:line-range references"
  PROOF_DONE=1; exit 0
fi
echo "VERDICT: claim not supported"
exit 1
