import { afterEach, describe, expect, it } from 'vitest'
import {
  detectPackageManager,
  normalizeTagToSemver,
  resolveBinaryUpdateConfig,
  selectGitHubAsset,
  selectGitLabAsset,
} from '../src/dimsdk/cli/binary-upgrade.ts'

const realProcess = globalThis.process
const realBunDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'Bun')

function setProcess(
  patch: Partial<
    Pick<NodeJS.Process, 'arch' | 'argv' | 'env' | 'execPath' | 'pid' | 'platform'>
  >,
): void {
  Object.defineProperty(globalThis, 'process', {
    configurable: true,
    value: {
      ...realProcess,
      ...patch,
    },
  })
}

function setBun(value: unknown): void {
  Object.defineProperty(globalThis, 'Bun', {
    configurable: true,
    value,
  })
}

afterEach(() => {
  Object.defineProperty(globalThis, 'process', {
    configurable: true,
    value: realProcess,
  })

  if (realBunDescriptor) {
    Object.defineProperty(globalThis, 'Bun', realBunDescriptor)
  }
  else {
    Reflect.deleteProperty(globalThis, 'Bun')
  }
})

describe('binary upgrade helpers', () => {
  it('normalizes release tags into semver', () => {
    expect(normalizeTagToSemver('v1.2.3')).toBe('1.2.3')
    expect(normalizeTagToSemver('1.2.3-beta.1')).toBe('1.2.3-beta.1')
    expect(normalizeTagToSemver('latest')).toBeNull()
    expect(normalizeTagToSemver('')).toBeNull()
  })

  it('detects bun from Bun runtime without any env fallback', () => {
    setProcess({ execPath: '/tmp/dim' })
    setBun({})

    expect(detectPackageManager()).toBe('bun')
  })

  it('detects npm from npm-global install paths', () => {
    setProcess({ execPath: '/Users/test/.npm-global/bin/dim' })

    expect(detectPackageManager()).toBe('npm')
  })

  it('selects a matching GitHub release asset from typed release data', () => {
    expect(
      selectGitHubAsset(
        {
          assets: [
            null,
            { name: 'dim-bun-linux-x64' },
            {
              name: 'dim-bun-linux-x64',
              browser_download_url: 'https://example.com/dim',
            },
          ],
        },
        'dim-bun-linux-x64',
      ),
    ).toEqual({
      name: 'dim-bun-linux-x64',
      url: 'https://example.com/dim',
    })
  })

  it('selects a matching GitLab asset and prefers direct asset urls', () => {
    expect(
      selectGitLabAsset(
        {
          assets: {
            links: [
              {
                name: 'dim-bun-linux-x64',
                url: 'https://example.com/redirect',
                direct_asset_url: 'https://example.com/direct',
              },
            ],
          },
        },
        'dim-bun-linux-x64',
      ),
    ).toEqual({
      name: 'dim-bun-linux-x64',
      url: 'https://example.com/direct',
    })
  })

  it('resolves github binary update config from env without extra shims', () => {
    expect(
      resolveBinaryUpdateConfig({
        DIMCODE_BINARY_UPDATE_PROVIDER: 'github',
        DIMCODE_BINARY_UPDATE_REPO: 'acme/dim',
        DIMCODE_BINARY_UPDATE_GITHUB_API_BASE_URL:
          'https://api.github.example.com///',
      }),
    ).toEqual({
      provider: 'github',
      project: 'acme/dim',
      githubApiBaseUrl: 'https://api.github.example.com',
    })
  })
})
