// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

import { isPosixPathSeparator } from "./_util.ts";
import { resolve } from "./resolve.ts";
import { assertArgs } from "../_common/relative.ts";

/**
 * Return the relative path from `from` to `to` based on current working directory.
 *
 * @param from path in current working directory
 * @param to path in current working directory
 */
export function relative(from: string, to: string): string {
  assertArgs(from, to);

  from = resolve(from);
  to = resolve(to);

  if (from === to) return "";

  // Trim any leading backslashes
  let fromStart = 1;
  const fromEnd = from.length;
  for (; fromStart < fromEnd; ++fromStart) {
    if (!isPosixPathSeparator(from.charCodeAt(fromStart))) break;
  }
  const fromLen = fromEnd - fromStart;

  // Trim any leading backslashes
  let toStart = 1;
  const toEnd = to.length;
  for (; toStart < toEnd; ++toStart) {
    if (!isPosixPathSeparator(to.charCodeAt(toStart))) break;
  }
  const toLen = toEnd - toStart;

  // Compare paths to find the longest common path from root
  const length = fromLen < toLen ? fromLen : toLen;
  let lastCommonSep = -1;
  let i = 0;
  for (; i <= length; ++i) {
    if (i === length) {
      if (toLen > length) {
        if (isPosixPathSeparator(to.charCodeAt(toStart + i))) {
          // We get here if `from` is the exact base path for `to`.
          // For example: from='/foo/bar'; to='/foo/bar/baz'
          return to.slice(toStart + i + 1);
        } else if (i === 0) {
          // We get here if `from` is the root
          // For example: from='/'; to='/foo'
          return to.slice(toStart + i);
        }
      } else if (fromLen > length) {
        if (isPosixPathSeparator(from.charCodeAt(fromStart + i))) {
          // We get here if `to` is the exact base path for `from`.
          // For example: from='/foo/bar/baz'; to='/foo/bar'
          lastCommonSep = i;
        } else if (i === 0) {
          // We get here if `to` is the root.
          // For example: from='/foo'; to='/'
          lastCommonSep = 0;
        }
      }
      break;
    }
    const fromCode = from.charCodeAt(fromStart + i);
    const toCode = to.charCodeAt(toStart + i);
    if (fromCode !== toCode) break;
    else if (isPosixPathSeparator(fromCode)) lastCommonSep = i;
  }

  let out = "";
  // Generate the relative path based on the path difference between `to`
  // and `from`
  for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
    if (i === fromEnd || isPosixPathSeparator(from.charCodeAt(i))) {
      if (out.length === 0) out += "..";
      else out += "/..";
    }
  }

  // Lastly, append the rest of the destination (`to`) path that comes after
  // the common path parts
  if (out.length > 0) return out + to.slice(toStart + lastCommonSep);
  else {
    toStart += lastCommonSep;
    if (isPosixPathSeparator(to.charCodeAt(toStart))) ++toStart;
    return to.slice(toStart);
  }
}

// denoCacheMetadata={"headers":{"cf-cache-status":"HIT","age":"44352","alt-svc":"h3=\":443\"; ma=86400","content-security-policy":"default-src 'none'; script-src 'none'; style-src 'none'; img-src 'none'; font-src 'none'; connect-src 'none'; frame-src 'none'; object-src 'none'; frame-ancestors 'none'; sandbox; form-action 'none';","cache-control":"public, max-age=31536000, immutable","date":"Tue, 28 Jul 2026 12:31:15 GMT","access-control-expose-headers":"*","server":"cloudflare","cf-ray":"a223e6585c187db6-LAX","x-content-type-options":"nosniff","set-cookie":"__cf_bm=cQev2bqQxrBF6p9hh9g7O.L7AihxD50TsLPQs_r0Nok-1785241875.2578876-1.0.1.1-KCPVWmQGgfbcbhCXAy1S8rPEA58V8xSVR14YD_7_fu_HGxsGONC6xCLXfOOyqAw_w.WxcSLyuVjJXWHokucf237ei3oVoFuNpEokZr.0Tu4TpgEdqdwd.LZFlh3fT6E9; HttpOnly; SameSite=None; Secure; Path=/; Domain=jsr.io; Expires=Tue, 28 Jul 2026 13:01:15 GMT","x-jsr-backend":"modules","report-to":"{\"group\":\"cf-nel\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://a.nel.cloudflare.com/report/v4?s=%2F%2B0RNm%2B6w5qYShylsMgjoIVe%2FI5%2FtQuGDekj5phDfTpBwbwBl%2B2wM%2BtcXITUc3tZ6tZQ6RNHgdMK%2BEOu4p0AfQTDlnP1wYFqSFWdij8UAtACFkm%2B5YbEDas%3D\"}]}","accept-ranges":"bytes","content-length":"3000","etag":"\"f7f7cb6b7fe5aa6a33577a32e87f0a1c\"","content-type":"text/typescript","vary":"Origin","x-robots-tag":"noindex","nel":"{\"report_to\":\"cf-nel\",\"success_fraction\":0.0,\"max_age\":604800}","cross-origin-resource-policy":"cross-origin","access-control-allow-origin":"*"},"url":"https://jsr.io/@std/path/0.224.0/posix/relative.ts","time":1785241875}