export default async function handleImports(
  sourceCode: string,
  sourcePath?: string
) {
  const sources: { [fileName: string]: { content: any } } = {}
  const importRegex = /import\s+(?:{[^}]+}\s+from\s+)?["']([^"']+)["'];/g
  const matches = Array.from(sourceCode.matchAll(importRegex))
  for (const match of matches) {
    const importPath = match[1]
    const { sources: importedSources, sourceCode: mainSourceCode } =
      await fetchImport(importPath, sourcePath)

    // Merge the imported sources into the main sources object
    Object.assign(sources, importedSources)

    let sourceFileName = importPath.split('/').pop() || importPath

    // if sources[sourceFileName] already exists and the content is the same, then skip, otherwise change the sourceFileName to keep the folder structure but still be a relative path
    if (
      sources[sourceFileName] &&
      sources[sourceFileName].content !== mainSourceCode
    ) {
      sourceFileName = importPath.split('/').slice(-2).join('/')
    }

    sources[sourceFileName] = {
      content: mainSourceCode
    }
    sourceCode = sourceCode.replace(match[0], `import "${sourceFileName}";`)
  }
  return { sources, sourceCode }
}

async function fetchImport(importPath: string, sourcePath?: string) {
  // Determine the URL to fetch
  let urlToFetch
  if (importPath[0] === '.' && sourcePath) {
    // If the import path starts with '.', it's a relative path, so resolve the path
    let finalPath = resolveImportPath(importPath, sourcePath)
    urlToFetch = finalPath
  } else if (importPath[0] !== '@') {
    // If the import path starts with anything other than '@', use it directly
    urlToFetch = importPath
  } else {
    // Otherwise, convert the import path to an unpkg URL
    urlToFetch = `https://unpkg.com/${importPath}`
  }
  // Convert GitHub URLs to raw content URLs
  if (urlToFetch.includes('github.com')) {
    urlToFetch = urlToFetch
      .replace('github.com', 'raw.githubusercontent.com')
      .replace('/blob/', '/')
  }

  // Fetch the imported file
  const response = await fetch(urlToFetch)

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`)
  }

  let importedSource = await response.text()

  // Handle any imports within the fetched source code
  const { sources, sourceCode } = await handleImports(
    importedSource,
    urlToFetch
  )

  return { sources, sourceCode }
}

/// utility function to handle relative paths
function resolveImportPath(importPath: string, sourcePath: string) {
  let importSegments = importPath.split('/')
  let sourceSegments = sourcePath.split('/')

  // Remove the last segment (file name) from the source path
  sourceSegments.pop()

  // Process each segment of the import path
  while (importSegments.length > 0 && importSegments[0] === '..') {
    // Remove one directory level for each '..'
    sourceSegments.pop()
    importSegments.shift()
  }

  // Special handling for './'
  if (importSegments.length > 0 && importSegments[0] === '.') {
    importSegments.shift()
  }

  // Reconstruct the final path
  return sourceSegments.concat(importSegments).join('/')
}
