import Handlebars from 'handlebars';
import chalk from 'chalk';
import { copyFile, cp, mkdir, readFile, rename, rm, stat, writeFile } from 'fs/promises';
import { join } from 'path';
import { PROJECT_DIR, COMPONENTS_DIR } from './meta';
import { logFileDeleted, logFileSavedTo } from './log';
import { existsSync } from 'fs';
const TEMPLATES_DIR = join(PROJECT_DIR, 'template');
const TEMP_PROJECT_DIR = join(PROJECT_DIR, '.build');
const compilePackage = async (componentName, subdir) => {
  if (subdir) {
    const exists = !!(await stat(join(COMPONENTS_DIR, subdir, componentName, 'package.json')).catch(() => {
      return false;
    }));
    if (exists) {
      console.log(`File package.json ${chalk.yellow('previously created')}, skipping it.`);
    }
    return await createPackage(componentName, subdir);
  }
  else {
    const exists = !!(await stat(join(COMPONENTS_DIR, componentName, 'package.json')).catch(() => {
      return false;
    }));
    if (exists) {
      console.log(`File package.json ${chalk.yellow('previously created')}, skipping it.`);
    }
    return await createPackage(componentName);
  }
};
const createPackage = async (componentName, subdir) => {
  const packageFile = await readFile(join(PROJECT_DIR, 'package.json')).catch(error => {
    throw Error(chalk.red(error));
  });
  const packageData = JSON.parse(packageFile.toString());
  const packageTemplate = await readFile(join(TEMPLATES_DIR, 'package.json')).catch(error => {
    throw Error(chalk.red(error));
  });
  const template = Handlebars.compile(packageTemplate.toString());
  // packageData: prende semplicemente le dipendenze e tutto il resto dal package.json da template.
  // bisogna inserire qua dentro anche le dipendenze relative ai singoli webcomponent incapsulati.
  // let dependenciesOtherWebcomponents;
  // if(subdir){
  //
  // const tsxFile = readFile(join(COMPONENTS_DIR,subdir, componentName+'.tsx')).catch(error => {
  //     throw Error(chalk.red(error));
  //   })
  //   // await tsxFile.then(res => {
  //   //   dependenciesOtherWebcomponents = JSON.stringify(res).split(/[:<sw-(.*)</sw:]/);
  //   //   JSON.stringify(res).split('<sw-').pop().split('>')[0];
  //   //   dependenciesOtherWebcomponents =JSON.stringify(res). JSON.stringify(res).includes('sw-')
  //   // })
  //
  //
  // }
  const data = {
    componentName: componentName,
    dependencies: JSON.stringify(packageData.dependencies, null, 4),
    author: JSON.stringify(packageData.author, null, 4),
    // contributors: JSON.stringify(packageData.contributors, null, 4),
  };
  const packageModule = template(data);
  if (subdir) {
    await writeFile(join(COMPONENTS_DIR, subdir, componentName, 'package.json'), packageModule, { encoding: 'utf8' })
      .then(() => {
      logFileSavedTo('package.json', COMPONENTS_DIR);
    })
      .catch(error => {
      throw Error(chalk.red(error));
    });
  }
  else {
    await writeFile(join(COMPONENTS_DIR, componentName, 'package.json'), packageModule, { encoding: 'utf8' })
      .then(() => {
      logFileSavedTo('package.json', COMPONENTS_DIR);
    })
      .catch(error => {
      throw Error(chalk.red(error));
    });
  }
};
const compileTemplateFile = async (componentName, fileName, subdir) => {
  if (subdir !== '' && subdir) {
    const exists = !!(await stat(join(COMPONENTS_DIR, subdir.toString(), componentName, fileName)).catch(() => {
      return false;
    }));
    if (exists) {
      console.log(`File ${fileName} of ${chalk.blue(componentName)} ${chalk.yellow('previously created')}, skipping it.`);
      return;
    }
    await createTemplateFile(componentName, fileName, subdir);
  }
  else {
    const exists = !!(await stat(join(COMPONENTS_DIR, componentName, fileName)).catch(() => {
      return false;
    }));
    if (exists) {
      console.log(`File ${fileName} of ${chalk.blue(componentName)} ${chalk.yellow('previously created')}, skipping it.`);
      return;
    }
    await createTemplateFile(componentName, fileName);
  }
};
const createTemplateFile = async (componentName, fileName, subdir) => {
  const packageTemplate = await readFile(join(TEMPLATES_DIR, fileName)).catch(error => {
    throw Error(chalk.red(error));
  });
  const template = Handlebars.compile(packageTemplate.toString());
  let templateCompiled;
  if (fileName === '.gitlab-ci.yml') {
    templateCompiled = template({ componentName: componentName.replace('sw-', '') });
  }
  else {
    templateCompiled = template({ componentName: componentName });
  }
  if (subdir !== '' && subdir) {
    await writeFile(join(COMPONENTS_DIR, subdir.toString(), componentName, fileName), templateCompiled, { encoding: 'utf8' })
      .then(() => {
      logFileSavedTo(fileName, COMPONENTS_DIR);
    })
      .catch(error => {
      throw Error(chalk.red(error));
    });
  }
  else {
    await writeFile(join(COMPONENTS_DIR, componentName, fileName), templateCompiled, { encoding: 'utf8' })
      .then(() => {
      logFileSavedTo(fileName, COMPONENTS_DIR);
    })
      .catch(error => {
      throw Error(chalk.red(error));
    });
  }
};
const scaffoldStencil = async (componentName) => {
  const fileName = 'stencil.config.ts';
  const stencilTemplate = await readFile(join(TEMPLATES_DIR, fileName)).catch(error => {
    throw Error(chalk.red(error));
  });
  const template = Handlebars.compile(stencilTemplate.toString());
  const data = {
    componentName: componentName
  };
  const stencilConfig = template(data);
  await writeFile(join(TEMP_PROJECT_DIR, componentName, fileName), stencilConfig, { encoding: 'utf8' })
    .then(() => {
    logFileSavedTo(fileName, componentName);
  })
    .catch(error => {
    throw Error(chalk.red(error));
  });
};
const createTempProjectInstance = async (componentName, subdir) => {
  const ISOLATED_PATH = join(TEMP_PROJECT_DIR, componentName);
  await mkdir(ISOLATED_PATH, { recursive: true }).catch(error => {
    throw Error(chalk.red(error));
  });
  await copyFile(join(PROJECT_DIR, 'tailwind.config.js'), join(ISOLATED_PATH, 'tailwind.config.js')).catch(error => {
    throw Error(chalk.red(error));
  });
  await copyFile(join(PROJECT_DIR, 'tsconfig.json'), join(ISOLATED_PATH, 'tsconfig.json')).catch(error => {
    throw Error(chalk.red(error));
  });
  await scaffoldStencil(componentName);
  await mkdir(join(ISOLATED_PATH, 'src'), { recursive: true }).catch(error => {
    throw Error(chalk.red(error));
  });
  // await cp(join(PROJECT_DIR, 'src/dictionary'), join(ISOLATED_PATH, 'src/dictionary'), { recursive: true }).catch(error => {
  //   throw Error(chalk.red(error));
  // });
  await cp(join(PROJECT_DIR, 'src/fixtures'), join(ISOLATED_PATH, 'src/fixtures'), { recursive: true }).catch(error => {
    throw Error(chalk.red(error));
  });
  await cp(join(PROJECT_DIR, 'src/tailwind'), join(ISOLATED_PATH, 'src/tailwind'), { recursive: true }).catch(error => {
    throw Error(chalk.red(error));
  });
  // await cp(join(PROJECT_DIR, 'src/interface'), join(ISOLATED_PATH, 'src/interface'), { recursive: true }).catch(error => {
  //   throw Error(chalk.red(error));
  // });
  // await cp(join(PROJECT_DIR, 'src/types'), join(ISOLATED_PATH, 'src/types'), { recursive: true }).catch(error => {
  //   throw Error(chalk.red(error));
  // });
  if (subdir && subdir !== '') {
    await cp(join(PROJECT_DIR, 'src/components', subdir, componentName), join(ISOLATED_PATH, 'src/components', subdir, componentName), {
      recursive: true,
    }).catch(error => {
      throw Error(chalk.red(error));
    });
    await rename(join(ISOLATED_PATH, 'src/components', subdir, componentName, 'package.json'), join(ISOLATED_PATH, 'package.json')).catch(error => {
      throw Error(chalk.red(error));
    });
    await rename(join(ISOLATED_PATH, 'src/components', subdir, componentName, 'readme.md'), join(ISOLATED_PATH, 'readme.md')).catch(error => {
      throw Error(chalk.red(error));
    });
  }
  else {
    await cp(join(PROJECT_DIR, 'src/components', componentName), join(ISOLATED_PATH, 'src/components', componentName), {
      recursive: true,
    }).catch(error => {
      throw Error(chalk.red(error));
    });
    await rename(join(ISOLATED_PATH, 'src/components', componentName, 'package.json'), join(ISOLATED_PATH, 'package.json')).catch(error => {
      throw Error(chalk.red(error));
    });
    await rename(join(ISOLATED_PATH, 'src/components', componentName, 'readme.md'), join(ISOLATED_PATH, 'readme.md')).catch(error => {
      throw Error(chalk.red(error));
    });
  }
  await copyFile(join(PROJECT_DIR, 'src/interfaces.d.ts'), join(ISOLATED_PATH, 'src/interfaces.d.ts')).catch(error => {
    throw Error(chalk.red(error));
  });
  await cp(join(PROJECT_DIR, 'src/utils'), join(ISOLATED_PATH, 'src/utils'), { recursive: true }).catch(error => {
    throw Error(chalk.red(error));
  });
};
const findPackageToDelete = async (componentName) => {
  let existsForShared = false;
  let existsForCustom = false;
  existsForShared = existsSync((join(COMPONENTS_DIR, 'shared', componentName, 'package.json')));
  if (existsForShared) {
    console.log(`File package.json ${chalk.yellow('previously created')}, preparing to delete it.`);
    return deletePackage('/shared/' + componentName);
  }
  else {
    console.log(`File package.json ${chalk.red('not previously created')}, skipping it`);
  }
  existsForCustom = existsSync((join(COMPONENTS_DIR, 'customs', componentName, 'package.json')));
  if (existsForCustom) {
    console.log(`File package.json ${chalk.yellow('previously created')}, preparing to delete it.`);
    return deletePackage('/customs/' + componentName);
  }
  else {
    console.log(`File package.json ${chalk.red('not previously created')}, skipping it`);
  }
};
const deletePackage = async (componentName) => {
  await rm(join(COMPONENTS_DIR, componentName, 'package.json'), { force: false })
    .then(() => {
    logFileDeleted('package.json', COMPONENTS_DIR);
  })
    .catch(error => {
    throw Error(chalk.red(error));
  });
};
const deleteGitlab = async (componentName) => {
  await rm(join(COMPONENTS_DIR, componentName, '.gitlab-ci.yml'), { force: true })
    .then(() => {
    logFileDeleted('.gitlab-ci.yml', COMPONENTS_DIR);
  })
    .catch(error => {
    throw Error(chalk.red(error));
  });
};
const findGitlabToDelete = async (componentName) => {
  const existsGitlabCiShared = existsSync((join(COMPONENTS_DIR, 'shared', componentName, '.gitlab-ci.yml')));
  if (existsGitlabCiShared) {
    console.log(`File Gitlab-ci ${chalk.yellow('previously created')}, preparing to delete it.`);
    return deleteGitlab('/shared/' + componentName);
  }
  else {
    console.log(`File Gitlab-ci ${chalk.red('not previously created')}, skipping it`);
  }
  const existsGitlabCiForCustom = existsSync((join(COMPONENTS_DIR, 'customs', componentName, '.gitlab-ci.yml')));
  if (existsGitlabCiForCustom) {
    console.log(`File Gitlab-ci ${chalk.yellow('previously created')}, preparing to delete it.`);
    return deleteGitlab('/customs/' + componentName);
  }
  else {
    console.log(`File Gitlab-ci ${chalk.red('not previously created')}, skipping it`);
  }
};
export { createTempProjectInstance, compilePackage, compileTemplateFile, findPackageToDelete, findGitlabToDelete };
