//@ts-nocheck
import * as _ from "lodash";
import * as mkdirp from "mkdirp";
import { dropDownList } from "./switch-frontend-snippet.comand";
import {
  itemOptions,
  quickPickOptions,
  inputPrompOptionForModuleName,
  inputPrompOptionForViewName,
} from "./new-trongate-module-dropdown-options";
import {
  getTrongateAssets,
  viewTemplate as tgViewTemplate,
  getTrongateModuleCss,
  getTongateControllerTemplate,
} from "./templates";

import { makeFirstLetterGoUpper, validateModuleName, checkIsTrongateProject } from "./utils/helper";

import {
  OpenDialogOptions,
  workspace,
  Uri,
  window,
  Position,
  Selection,
} from "vscode";
import { existsSync, lstatSync, writeFile, readFileSync} from "fs";
import * as path from 'path'
import * as slash from 'slash'

// Entry point
export const newModule = async (uri: Uri) => {

    // check if it is a trongate project
    const GLOBAL_SETTINGS = {
      projectPath: '',
      isTrongateProject: false,
      config: {},
    }
    try {
      GLOBAL_SETTINGS['projectPath'] = workspace.workspaceFolders[0].uri.fsPath
      GLOBAL_SETTINGS['isTrongateProject'] = checkIsTrongateProject(GLOBAL_SETTINGS.projectPath)
      if (GLOBAL_SETTINGS['isTrongateProject']) {
        //read all the configs from config file
        const configFilePath = path.join(GLOBAL_SETTINGS['projectPath'], 'config', 'config.php')
        const configFileContent = readFileSync(configFilePath, { encoding: 'utf8' });
        const regexMatch = /define\(\s*('\w+'|"\w+"\1)\s*,\s*('\w+'|"\w+"\2)\s*\)/
        configFileContent.split('\n').map(item => {
          const match = item.match(regexMatch)
          if (match) {
            const configKey = match[1].split('').filter(item => item !== '\'' && item !== '"').join('')
            const configValue = match[2].split('').filter(item => item !== '\'' && item !== '"').join('')
            GLOBAL_SETTINGS['config'][configKey] = configValue
          }
        })
      }
    } catch (error) {
      console.log(error)
    }

    if (!GLOBAL_SETTINGS['isTrongateProject']) {
      window.showErrorMessage("The current workspace does not contain a valid Trongate Project");
      return
    }

  // console.log('===================')
  // console.log(uri) 
  // console.log(GLOBAL_SETTINGS) 
  // console.log('===================')

  /**
   * The function starts from here
   */
  const moduleName = await prompForInput(inputPrompOptionForModuleName);
  console.log(moduleName);
  if (_.isNil(moduleName) || moduleName.trim() === "") {
    window.showErrorMessage("The module name must not be empty");
    return;
  }

  // check if the module name contains the assets trigger phase
  const validName = validateModuleName(moduleName)
  if (validName.includes(GLOBAL_SETTINGS['config']['MODULE_ASSETS_TRIGGER'])) {
    window.showErrorMessage(`Your module name contained the MODULE_ASSETS_TRIGGER: ${GLOBAL_SETTINGS['config']['MODULE_ASSETS_TRIGGER']}, please rename your module`);
    return
  }

  let targetDirectory;
  if (_.isNil(_.get(uri, "fsPath")) || !lstatSync(uri.fsPath).isDirectory()) {
    targetDirectory = await promptForTargetDirectory();
    if (_.isNil(targetDirectory)) {
      window.showErrorMessage("Please select a valid directory");
      return;
    }
  } else {
    targetDirectory = uri.fsPath;
  }

  const isViewTemplate = await dropDownList(itemOptions, quickPickOptions);

  // There is a possibility that the user presses ESC then we cancel the process
  // and return an error message to the user
  if (isViewTemplate === undefined) {
    window.showErrorMessage("Process cancelled, no new module created");
    return;
  }

  let viewFileName;
  if (isViewTemplate === "yes") {
    // promp window for a view file name
    viewFileName = await prompForInput(inputPrompOptionForViewName);
    if (_.isNil(viewFileName) || viewFileName.trim() === "") {
      window.showErrorMessage("The view file name must not be empty");
      return;
    }
    viewFileName = viewFileName.split(" ").join("_");
  }

  const genObj = {
    moduleName,
    targetDirectory,
    isViewTemplate,
    viewFileName,
    GLOBAL_SETTINGS
  };
  try {
    await generateModuleCode(genObj);
    // Open the controller file and put curosr at the correct position
    openEditorAndPutCursorAtGoodPosition(
      targetDirectory,
      moduleName,
      isViewTemplate
    );

    const pascalCaseBlocName = validateModuleName(moduleName); // implement this later - change all the space to underscore
    window.showInformationMessage(
      `Successfully Generated ${pascalCaseBlocName} Module`
    );
  } catch (error) {
    window.showErrorMessage(
      `Error:
        ${error instanceof Error ? error.message : JSON.stringify(error)}`
    );
    console.log(error);
  }
};

function prompForInput(promotOptions): Thenable<string | undefined> {
  return window.showInputBox(promotOptions);
}

async function promptForTargetDirectory(): Promise<string | undefined> {
  const options: OpenDialogOptions = {
    canSelectMany: false,
    openLabel: "Select a folder to create the module in",
    canSelectFolders: true,
  };

  return window.showOpenDialog(options).then((uri) => {
    if (_.isNil(uri) || _.isEmpty(uri)) {
      return undefined;
    }
    return uri[0].fsPath;
  });
}

async function generateModuleCode({
  moduleName,
  targetDirectory,
  isViewTemplate,
  viewFileName,
  GLOBAL_SETTINGS
}) {
  const validatedName = validateModuleName(moduleName);

  targetDirectory = slash(targetDirectory)
  console.log(targetDirectory)
  if(targetDirectory.split('/').slice(-1)[0] === 'modules') {
    GLOBAL_SETTINGS['superModule'] = false;
    GLOBAL_SETTINGS['parentModuleName'] = 'modules'
  } else {
    GLOBAL_SETTINGS['superModule'] = true
    GLOBAL_SETTINGS['parentModuleName'] = targetDirectory.split('/').slice(-1)[0]
  }
  // console.log('============================>')
  // console.log(targetDirectory.split('/').slice(-1)[0])
  // console.log(GLOBAL_SETTINGS)
  // console.log('============================>')
  const moduleDirectoryPath = `${targetDirectory}/${validatedName}`;
  if (!existsSync(moduleDirectoryPath)) {
    await createDirectory(moduleDirectoryPath);
  }

  await Promise.all([
    createTrongateModuleTemplate(
      validatedName,
      moduleDirectoryPath,
      isViewTemplate,
      viewFileName,
      GLOBAL_SETTINGS
    ),
  ]);
}

function createDirectory(targetDirectory: string): Promise<void> {
  return new Promise((resolve, reject) => {
    // TODO: handle this error in a proper way
    mkdirp(targetDirectory, (error) => {
      if (error) {
        return reject(error);
      }
      resolve();
    });
  });
}

async function createTrongateModuleTemplate(
  moduleName: string,
  targetDirectory: string,
  isViewTemplate: string,
  viewFileName: string,
  GLOBAL_SETTINGS: any
) {
  // The moduleName has been validated - this means no space and all lowercases

  /* upperModuleName is the name for controller php file,
    therefore the first letter needs to be uppercase */
  const upperModuleName = makeFirstLetterGoUpper(moduleName);
  await createDirectory(`${targetDirectory}/controllers`);
  await createDirectory(`${targetDirectory}/views`);
  await createDirectory(`${targetDirectory}/assets`);
  if (isViewTemplate == "yes") {
    await createDirectory(`${targetDirectory}/assets/css`);
    await createDirectory(`${targetDirectory}/assets/js`);
  }

  // const isSuperModule = GLOBAL_SETTINGS['superModule']

  // 1. check workspace - engine/ config/ modules -> pass -> this is a trongate project
  // 2. trigger language server
  // 3. communicate

  const targetControllerPath = `${targetDirectory}/controllers/${upperModuleName}.php`;
  let targetViewPath;
  let targetCSSPath;
  let targetJSPath;
  if (isViewTemplate == "yes") {
    targetViewPath = `${targetDirectory}/views/${viewFileName}.php`;
    targetCSSPath = `${targetDirectory}/assets/css/custom.css`;
    targetJSPath = `${targetDirectory}/assets/js/custom.js`;
  }
  const targetApiPath = `${targetDirectory}/assets/api.json`;
  if (existsSync(targetControllerPath)) {
    throw Error(`Module ${moduleName} already exists`);
  }
  await Promise.all([
    writeFile(
      targetControllerPath,
      getTongateControllerTemplate(GLOBAL_SETTINGS, moduleName, viewFileName),
      "utf8",
      (error) => {
        console.log(error);
      }
    ),
    // Write JS File
    isViewTemplate === "yes" &&
      writeFile(
        targetJSPath,
        "// Add your JavaScript here",
        "utf8",
        (error) => {
          console.log(error);
        }
      ),
    // Write View File
    isViewTemplate === "yes" &&
      writeFile(
        targetViewPath,
        getTrongateViewTemplate(moduleName, GLOBAL_SETTINGS),
        "utf8",
        (error) => {
          console.log(error);
        }
      ),
    // Write CSS File
    isViewTemplate === "yes" &&
      writeFile(targetCSSPath, getTrongateModuleCss(), "utf8", (error) => {
        console.log(error);
      }),

    // Write Assets file
    writeFile(targetApiPath, getTrongateAssets(moduleName), "utf8", (error) => {
      console.log(error);
    }),
  ]).catch((err) => {
    console.log(err);
  });
}

function getTrongateViewTemplate(moduleName: string, GLOBAL_SETTINGS): string {
  const displayModuleName = validateModuleName(moduleName);
  return tgViewTemplate(displayModuleName, GLOBAL_SETTINGS);
}

// Helper Function to open the controller file and place curosr at good position
function openEditorAndPutCursorAtGoodPosition(
  targetDirectory,
  moduleName,
  isViewTemplate
) {
  const validatedModuleName = validateModuleName(moduleName);
  const upperModuleName = makeFirstLetterGoUpper(validatedModuleName);
  const controllerLocation = `${targetDirectory}/${validatedModuleName}/controllers/${upperModuleName}.php`;
  var setting: vscode.Uri = Uri.file(controllerLocation);
  setting = setting.fsPath;
  workspace.openTextDocument(setting).then((document) =>
    window.showTextDocument(document).then((e) => {
      e.selections =
        isViewTemplate === "no"
          ? [new Selection(new Position(0, 5), new Position(0, 5))]
          : [new Selection(new Position(0, 5), new Position(0, 5))];
    })
  );
}