/**
 * Git remote URL utilities — GitHub-focused.
 *
 * Parsing, validation, and compare-URL generation for git remote URLs.
 * Used by both the UI and the vite-plugin-file-sync AI agent tooling.
 */

const HTTPS_GIT_URL_RE = /^https?:\/\/[^\s/$.?#]+\.[^\s/$.?#]+\/[^\s/$.?#]+(\/[^\s/$.?#]+)+(\.git)?\/?$/i;
const SSH_GIT_URL_RE = /^[\w-]+@[\w.-]+:[\w./-]+(\.git)?$/;

export const GITHUB_PAT_SETTINGS_URL = 'https://github.com/settings/tokens';

export function isValidGitUrl(url: string): boolean {
  const trimmed = url.trim();
  return HTTPS_GIT_URL_RE.test(trimmed) || SSH_GIT_URL_RE.test(trimmed);
}

export function isGitHubUrl(url: string): boolean {
  const trimmed = url.trim();

  try {
    const parsed = new URL(trimmed);
    if (parsed.hostname.toLowerCase() === 'github.com') return true;
  } catch {
    // Not a valid URL — try SSH format
  }

  const sshMatch = trimmed.match(/^[\w-]+@([\w.-]+):/);
  if (sshMatch?.[1]?.toLowerCase() === 'github.com') return true;

  return false;
}

/**
 * Converts a git remote URL (HTTPS or SSH) to a browser-friendly HTTPS URL.
 * Returns `null` when the URL cannot be converted.
 *
 *   https://github.com/org/repo.git  →  https://github.com/org/repo
 *   git@github.com:org/repo.git      →  https://github.com/org/repo
 */
export function gitRemoteUrlToWeb(url: string): string | null {
  const trimmed = url.trim();

  try {
    const parsed = new URL(trimmed);
    if (parsed.protocol === 'https:' || parsed.protocol === 'http:') {
      return trimmed.replace(/\.git\s*$/, '');
    }
  } catch {
    // Not a standard URL — try SSH
  }

  const sshMatch = trimmed.match(/^[\w-]+@([\w.-]+):(.+?)(?:\.git)?\s*$/);
  if (sshMatch?.[1] && sshMatch[2]) {
    return `https://${sshMatch[1]}/${sshMatch[2]}`;
  }

  return null;
}

/**
 * Returns a URL that opens the "new pull request" compare screen on GitHub.
 * Returns `null` when the remote URL is not a GitHub URL or cannot be parsed.
 */
export function getGitHubCompareUrl({
  gitRemoteUrl,
  fromBranch,
  toBranch,
  title,
  body
}: {
  gitRemoteUrl: string;
  fromBranch: string;
  toBranch: string;
  title?: string;
  body?: string;
}): string | null {
  if (!isGitHubUrl(gitRemoteUrl)) return null;

  const webUrl = gitRemoteUrlToWeb(gitRemoteUrl);
  if (!webUrl) return null;

  const base = `${webUrl}/compare/${encodeURIComponent(toBranch)}...${encodeURIComponent(fromBranch)}`;
  if (!title && !body) return base;

  const params = new URLSearchParams();
  params.set('expand', '1');
  if (title) params.set('title', title);
  if (body) params.set('body', body);
  return `${base}?${params.toString()}`;
}

type GitProvider = 'github' | 'gitlab' | 'bitbucket' | 'unknown';

const HOST_TO_PROVIDER: Record<string, GitProvider> = {
  'bitbucket.org': 'bitbucket',
  'github.com': 'github',
  'gitlab.com': 'gitlab'
};

function detectGitProvider(url: string): GitProvider {
  const trimmed = url.trim();

  try {
    const parsed = new URL(trimmed);
    return HOST_TO_PROVIDER[parsed.hostname.toLowerCase()] ?? 'unknown';
  } catch {
    // Not a standard URL — try SSH format.
  }

  const sshMatch = trimmed.match(/^[\w-]+@([\w.-]+):/);
  if (sshMatch?.[1]) {
    return HOST_TO_PROVIDER[sshMatch[1].toLowerCase()] ?? 'unknown';
  }

  return 'unknown';
}

function getCommitPathForProvider(params: { hash: string; provider: GitProvider }): string {
  const { hash, provider } = params;
  switch (provider) {
    case 'bitbucket':
      return `/commits/${hash}`;
    case 'gitlab':
      return `/-/commit/${hash}`;
    case 'github':
    case 'unknown':
      return `/commit/${hash}`;
  }
}

const GIT_COMMIT_HASH_REGEX = /^[0-9a-f]{7,40}$/i;

export function isGitCommitHash(value: string): boolean {
  return GIT_COMMIT_HASH_REGEX.test(value.trim());
}

export function getCommitUrlForHash(params: { hash: string; repositoryWebUrl: string }): string | null {
  const { hash, repositoryWebUrl } = params;
  const trimmedHash = hash.trim();
  if (!isGitCommitHash(trimmedHash)) {
    return null;
  }

  const trimmedRepositoryUrl = repositoryWebUrl.trim();
  const webUrl = gitRemoteUrlToWeb(trimmedRepositoryUrl) ?? trimmedRepositoryUrl;
  const provider = detectGitProvider(trimmedRepositoryUrl);

  return `${webUrl.replace(/\/+$/, '')}${getCommitPathForProvider({
    hash: trimmedHash,
    provider
  })}`;
}

export function isCommitUrlForHash(params: { hash: string; url: string }): boolean {
  const { hash, url } = params;
  const trimmedHash = hash.trim();
  const trimmedUrl = url.trim();
  if (!isGitCommitHash(trimmedHash)) {
    return false;
  }

  try {
    const parsed = new URL(trimmedUrl);
    const normalizedPathname = parsed.pathname.replace(/\/+$/, '');
    return normalizedPathname.endsWith(
      getCommitPathForProvider({
        hash: trimmedHash,
        provider: detectGitProvider(trimmedUrl)
      })
    );
  } catch {
    return false;
  }
}
