import { Logger } from 'winston';
import { join, posix } from 'path';
import { homedir } from 'os';
import { VENV, VENV_SCRIPTS_ACTIVATE, VENV_BIN_ACTIVATE } from '../../paths';
import { ALWAYSAI_OS_PLATFORM } from '../../environment';
import { TargetConfig } from './target-json-file';
import { Spawner } from '../../util/spawner';

export interface PythonVenvPaths {
  pythonExe: string;
  pythonVenvExe: string;
  activatePath: string;
}

export async function getPythonVenvPaths(props: {
  targetCfg: TargetConfig;
}): Promise<PythonVenvPaths> {
  const { targetCfg } = props;
  switch (targetCfg.targetProtocol) {
    case 'native:': {
      if (ALWAYSAI_OS_PLATFORM === 'win32') {
        return {
          pythonExe: join(homedir(), '.alwaysai', 'python', 'python.exe'),
          pythonVenvExe: join(VENV, 'Scripts', 'python.exe'),
          activatePath: VENV_SCRIPTS_ACTIVATE
        };
      }
      return {
        pythonExe: join(homedir(), '.alwaysai', 'python', 'bin', 'python3'),
        pythonVenvExe: join(VENV, 'bin', 'python'),
        activatePath: VENV_BIN_ACTIVATE
      };
    }
    case 'docker:':
    case 'ssh+docker:': {
      return {
        pythonExe: targetCfg.targetHardware.includes('jetson')
          ? 'python3'
          : 'python',
        pythonVenvExe: posix.join(VENV, 'bin', 'python'),
        activatePath: VENV_BIN_ACTIVATE
      };
    }
    default:
      throw new Error(`Invalid target protocol!`);
  }
}

export async function createPythonVenv(props: {
  targetSpawner: Spawner;
  pythonVenvPaths: PythonVenvPaths;
  logger: Logger;
}) {
  const { targetSpawner, pythonVenvPaths, logger } = props;
  if (await targetSpawner.exists(pythonVenvPaths.activatePath)) {
    return false;
  }
  logger.debug(
    await targetSpawner.run({
      exe: pythonVenvPaths.pythonExe,
      args: ['-m', VENV, '--system-site-packages', VENV],
      cwd: '.'
    })
  );
  // Update pip and setuptools from the default version provided by venv
  logger.debug(
    await targetSpawner.run({
      exe: pythonVenvPaths.pythonVenvExe,
      args: ['-m', 'pip', 'install', '--upgrade', 'pip', 'setuptools'],
      cwd: '.'
    })
  );
  return true;
}

export async function installPythonReqs(props: {
  reqFilePath: string;
  targetSpawner: Spawner;
  pythonVenvPaths: PythonVenvPaths;
  logger: Logger;
}) {
  const { reqFilePath, targetSpawner, pythonVenvPaths, logger } = props;
  logger.debug(
    await targetSpawner.run({
      exe: pythonVenvPaths.pythonVenvExe,
      args: ['-m', 'pip', 'install', '--requirement', reqFilePath]
    })
  );
  // uninstall conflicting packages that may have been installed
  logger.debug(
    await targetSpawner.run({
      exe: pythonVenvPaths.pythonVenvExe,
      args: [
        '-m',
        'pip',
        'uninstall',
        '-y',
        'opencv-python',
        'opencv-python-headless',
        'opencv-contrib-python-headless'
      ]
    })
  );
}
