import * as path from 'path'
import * as fs from 'fs/promises'
import { Models } from '@kittycad/lib/dist/types/src'
import { PROJECT_ENTRYPOINT } from './constants'

// Create a const object with the values
const FILE_IMPORT_FORMATS = {
  fbx: 'fbx',
  gltf: 'gltf',
  obj: 'obj',
  ply: 'ply',
  sldprt: 'sldprt',
  step: 'step',
  stl: 'stl',
} as const

// Extract the values into an array
const fileImportFormats: Models['FileImportFormat_type'][] =
  Object.values(FILE_IMPORT_FORMATS)
export const allFileImportFormats: string[] = [
  ...fileImportFormats,
  'stp',
  'fbxb',
  'glb',
]
export const relevantExtensions = ['kcl', ...allFileImportFormats]

/// Get the current project file from the path.
/// This is used for double-clicking on a file in the file explorer,
/// or the command line args, or deep linking.
export default async function getCurrentProjectFile(
  pathString: string
): Promise<string | Error> {
  // Fix for "." path, which is the current directory.
  let sourcePath = pathString === '.' ? process.cwd() : pathString

  // URL decode the path.
  sourcePath = decodeURIComponent(sourcePath)

  // If the path does not start with a slash, it is a relative path.
  // We need to convert it to an absolute path.
  sourcePath = path.isAbsolute(sourcePath)
    ? sourcePath
    : path.join(process.cwd(), sourcePath)

  // If the path is a directory, let's assume it is a project directory.
  const stats = await fs.stat(sourcePath)
  if (stats.isDirectory()) {
    // Walk the directory and look for a kcl file.
    const files = await fs.readdir(sourcePath)
    const kclFiles = files.filter((file) => path.extname(file) === '.kcl')

    if (kclFiles.length === 0) {
      let projectFile = path.join(sourcePath, PROJECT_ENTRYPOINT)
      // Check if we have a main.kcl file in the project.
      try {
        await fs.access(projectFile)
      } catch {
        // Create the default file in the project.
        await fs.writeFile(projectFile, '')
      }

      return projectFile
    }

    // If a project entrypoint file exists, use it.
    // Otherwise, use the first kcl file in the project.
    const gotMain = files.filter((file) => file === PROJECT_ENTRYPOINT)
    if (gotMain.length === 0) {
      return path.join(sourcePath, kclFiles[0])
    }
    return path.join(sourcePath, PROJECT_ENTRYPOINT)
  }

  // Check if the extension on what we are trying to open is a relevant file type.
  const extension = path.extname(sourcePath).slice(1)

  if (!relevantExtensions.includes(extension) && extension !== 'toml') {
    return new Error(
      `File type (${extension}) cannot be opened with this app: '${sourcePath}', try opening one of the following file types: ${relevantExtensions.join(
        ', '
      )}`
    )
  }

  // We were given a file path, not a directory.
  // Let's get the parent directory of the file.
  const parent = path.dirname(sourcePath)

  // If we got an import model file, we need to check if we have a file in the project for
  // this import model.
  if (allFileImportFormats.includes(extension)) {
    const importFileName = path.basename(sourcePath)
    // Check if we have a file in the project for this import model.
    const kclWrapperFilename = `${importFileName}.kcl`
    const kclWrapperFilePath = path.join(parent, kclWrapperFilename)

    try {
      await fs.access(kclWrapperFilePath)
    } catch {
      // Create the file in the project with the default import content.
      const content = `// This file was automatically generated by the application when you
// double-clicked on the model file.
// You can edit this file to add your own content.
// But we recommend you keep the import statement as it is.
// For more information on the import statement, see the documentation at:
// https://zoo.dev/docs/kcl/import
const model = import("${importFileName}")`
      await fs.writeFile(kclWrapperFilePath, content)
    }

    return kclWrapperFilePath
  }

  return sourcePath
}
