"""
Implementation of pip-based installation of openai.  This is no longer used since
openai is now included in Wing.  It could be the basis for similar installation
support for plugins in general.

Copyright (c) 1999-2024, Archaeopteryx Software, Inc.  All rights reserved.

Written by Stephan R.A. Deibel and John P. Ehresman
"""

import os
import sys

from _openai_completion import _GetPyExec

def _GetInstallArgs():

  # Output from 'PYTHONPATH=/path/to/site-packages /path/to/python -m pip freeze'
  PACKAGES = """
        annotated-types==0.6.0
        anyio==4.2.0
        certifi==2023.11.17
        distro==1.8.0
        h11==0.14.0
        httpcore==1.0.2
        httpx==0.26.0
        idna==3.6
        openai==1.6.0
        pydantic==2.5.3
        pydantic_core==2.14.6
        sniffio==1.3.0
        tqdm==4.66.1
        typing_extensions==4.9.0        
    """

  packages = []
  for package in PACKAGES.splitlines():
    package = package.strip()
    if package:
      packages.append(package)

  install_prefix, install_dir = _FindInstallDirs()
  pyexec = _GetPyExec()
  args = [pyexec, '-m', 'pip', 'install', '--prefix', install_prefix + os.sep + 'openai'] + packages
  return args

def _FindInstallDirs():
  """Get the location of install prefix and the directory that needs to be added to
  the Python path in order to use the openai package"""

  import _winghome

  install_prefix = os.path.join(_winghome.kUserSettings, 'ai')

  pyver = '{}.{}'.format(sys.version_info.major,
                           sys.version_info.minor)

  rt_dir = f'{install_prefix}{os.sep}openai'
  if sys.platform == 'win32':
    pypath_dir = fr'{rt_dir}\Lib\site-packages'
  else:
    pypath_dir = f'{rt_dir}/lib/python{pyver}/site-packages'

  return install_prefix, pypath_dir

def _InstallationNeeded():
  """Determine whether installation of openai dependencies is needed.  Returns
  (needed, action) where needed is True only if the installations is needed and
  action describes what the installation will do."""

  from wingbase import spawn

  install_prefix, install_dir = _FindInstallDirs()
  args = _GetInstallArgs()

  action = (
      ("The package 'openai' and its dependencies will be written to {} with "
         "the following command:").format(install_dir) + '\n\n' +
        spawn._win32_cmd_line_from_argv(args)
    )

  return not os.path.exists(os.path.join(install_dir, 'openai')), action

def _InstallDependencies(result_cb):
  """Install openai into Python using pip and --prefix option to place it into the user
  directory. Calls result_cb with (error, output) as the installation progress. If error
  is not None, the process has failed and error contains the error string. If output is
  not None the process is running and has printed output. If both error and output are
  None then the process has completed successfully."""

  from wingbase import spawn
  from ai import _

  install_prefix, install_dir = _FindInstallDirs()
  os.makedirs(install_prefix + os.sep + 'openai', exist_ok=True)

  if os.path.exists(install_dir):
    return

  args = _GetInstallArgs()
  proc = spawn.CChildProcess(args)

  result_cb(None, "Installing OpenAI with command:"+'\n'+spawn._win32_cmd_line_from_argv(args)+'\n')

  def start_failed(proc, exc):
    result_cb(_("Failed to start OpenAI installation process, with the following error:") + \
                  '\n\n' + exc, None)

  proc.connect('start-failed', start_failed)

  def terminated(proc):
    exit_code = proc.GetExitCode()
    if exit_code != 0:
      result_cb(_("The OpenAI installation process failed with exit code {}").format(exit_code) + '\n', None)
    elif not os.path.exists(install_dir):
      result_cb(_("The OpenAI installation did not create expected directory {}").format(install_dir) + '\n', None)
    else:
      result_cb(None, None)

  proc.connect('terminated', terminated)

  def received_output(proc, output):
    result_cb(None, output)

  proc.connect('received-output', received_output)

  proc.Start()

