import { describe, expect, it } from 'vitest';

import {
  GITHUB_PAT_SETTINGS_URL,
  getGitHubCompareUrl,
  gitRemoteUrlToWeb,
  isGitHubUrl,
  isValidGitUrl,
  sshGitUrlToHttps
} from './git-url.js';

describe('isValidGitUrl', () => {
  it.each([
    'https://github.com/org/repo.git',
    'https://github.com/org/repo',
    'http://gitlab.com/org/repo.git',
    'https://gitlab-pr-18183.superblocks.dev/root/ndavid.git',
    'git@github.com:org/repo.git',
    'git@gitlab.com:org/repo'
  ])('returns true for %s', (url) => {
    expect(isValidGitUrl(url)).toBe(true);
  });

  it.each(['', 'not-a-url', 'ftp://github.com/org/repo', 'https://', 'https://github.com/org'])('returns false for %j', (url) => {
    expect(isValidGitUrl(url)).toBe(false);
  });

  it('trims whitespace', () => {
    expect(isValidGitUrl('  https://github.com/org/repo  ')).toBe(true);
  });
});

describe('isGitHubUrl', () => {
  it.each(['https://github.com/org/repo.git', 'https://github.com/org/repo', 'git@github.com:org/repo.git'])(
    'returns true for %s',
    (url) => {
      expect(isGitHubUrl(url)).toBe(true);
    }
  );

  it.each(['https://gitlab.com/org/repo', 'git@bitbucket.org:org/repo.git', 'https://example.com/org/repo', 'not-a-url'])(
    'returns false for %s',
    (url) => {
      expect(isGitHubUrl(url)).toBe(false);
    }
  );

  it('is case-insensitive on the host', () => {
    expect(isGitHubUrl('https://GitHub.COM/org/repo')).toBe(true);
  });
});

describe('gitRemoteUrlToWeb', () => {
  it.each<[string, string]>([
    ['https://github.com/org/repo.git', 'https://github.com/org/repo'],
    ['https://github.com/org/repo', 'https://github.com/org/repo'],
    ['http://gitlab.com/org/repo.git', 'http://gitlab.com/org/repo'],
    ['git@github.com:org/repo.git', 'https://github.com/org/repo'],
    ['git@gitlab.com:group/sub/repo.git', 'https://gitlab.com/group/sub/repo'],
    // Azure DevOps HTTPS with userinfo (clone URL default format)
    ['https://myorg@dev.azure.com/myorg/myproject/_git/myrepo', 'https://dev.azure.com/myorg/myproject/_git/myrepo'],
    // Azure DevOps SSH formats
    ['git@ssh.dev.azure.com:v3/myorg/myproject/myrepo', 'https://dev.azure.com/myorg/myproject/_git/myrepo'],
    ['ssh://git@ssh.dev.azure.com/v3/myorg/myproject/myrepo', 'https://dev.azure.com/myorg/myproject/_git/myrepo']
  ])('converts %s → %s', (input, expected) => {
    expect(gitRemoteUrlToWeb(input)).toBe(expected);
  });

  it('strips userinfo from HTTPS URLs', () => {
    expect(gitRemoteUrlToWeb('https://myorg@dev.azure.com/myorg/myproject/_git/myrepo')).toBe(
      'https://dev.azure.com/myorg/myproject/_git/myrepo'
    );
  });

  it('returns null for unconvertible URLs', () => {
    expect(gitRemoteUrlToWeb('not-a-url')).toBeNull();
  });
});

describe('getGitHubCompareUrl', () => {
  const base = { fromBranch: 'feature/cool', toBranch: 'main' };

  it('builds a GitHub compare URL', () => {
    expect(
      getGitHubCompareUrl({
        gitRemoteUrl: 'https://github.com/org/repo.git',
        ...base
      })
    ).toBe('https://github.com/org/repo/compare/main...feature%2Fcool');
  });

  it('appends title and body', () => {
    expect(
      getGitHubCompareUrl({
        gitRemoteUrl: 'https://github.com/org/repo.git',
        ...base,
        title: 'My PR',
        body: '## Summary'
      })
    ).toBe('https://github.com/org/repo/compare/main...feature%2Fcool?expand=1&title=My+PR&body=%23%23+Summary');
  });

  it('returns null for non-GitHub URLs', () => {
    expect(
      getGitHubCompareUrl({
        gitRemoteUrl: 'https://gitlab.com/org/repo',
        ...base
      })
    ).toBeNull();
  });

  it('returns null for unconvertible URLs', () => {
    expect(getGitHubCompareUrl({ gitRemoteUrl: 'not-a-url', ...base })).toBeNull();
  });
});

describe('sshGitUrlToHttps', () => {
  it.each<[string, string]>([
    ['git@github.com:org/repo.git', 'https://github.com/org/repo.git'],
    ['git@github.com:org/repo', 'https://github.com/org/repo.git'],
    ['git@gitlab.com:group/sub/repo.git', 'https://gitlab.com/group/sub/repo.git'],
    ['git@gitlab-pr-17501.superblocks.dev:root/iojitest.git', 'https://gitlab-pr-17501.superblocks.dev/root/iojitest.git'],
    ['git@bitbucket.org:org/repo.git', 'https://bitbucket.org/org/repo.git'],
    ['ssh://git@github.com/org/repo.git', 'https://github.com/org/repo.git'],
    ['ssh://git@github.com/org/repo', 'https://github.com/org/repo.git'],
    ['git@ssh.dev.azure.com:v3/myorg/myproject/myrepo', 'https://dev.azure.com/myorg/myproject/_git/myrepo'],
    ['ssh://git@ssh.dev.azure.com/v3/myorg/myproject/myrepo', 'https://dev.azure.com/myorg/myproject/_git/myrepo']
  ])('converts %s → %s', (input, expected) => {
    expect(sshGitUrlToHttps(input)).toBe(expected);
  });

  it('returns HTTPS URLs unchanged', () => {
    expect(sshGitUrlToHttps('https://github.com/org/repo.git')).toBe('https://github.com/org/repo.git');
  });

  it('appends .git suffix when missing on HTTPS passthrough', () => {
    expect(sshGitUrlToHttps('https://github.com/org/repo')).toBe('https://github.com/org/repo.git');
  });

  it('does NOT append .git suffix to Azure DevOps HTTPS URLs', () => {
    expect(sshGitUrlToHttps('https://dev.azure.com/myorg/myproject/_git/myrepo')).toBe('https://dev.azure.com/myorg/myproject/_git/myrepo');
  });

  it('handles Azure DevOps HTTPS URLs with userinfo', () => {
    expect(
      sshGitUrlToHttps('https://superblocks-azure@dev.azure.com/superblocks-azure/Superblocks%20Devops%20Azure%20Test/_git/david-sb-gh')
    ).toBe('https://superblocks-azure@dev.azure.com/superblocks-azure/Superblocks%20Devops%20Azure%20Test/_git/david-sb-gh');
  });

  it('returns null for unconvertible URLs', () => {
    expect(sshGitUrlToHttps('not-a-url')).toBeNull();
  });
});

describe('GITHUB_PAT_SETTINGS_URL', () => {
  it('is a valid URL', () => {
    expect(GITHUB_PAT_SETTINGS_URL).toBe('https://github.com/settings/tokens');
  });
});
