'use strict';

function isPlainObject(value) {
  return value !== null && typeof value === 'object' && !Array.isArray(value);
}

function cloneScope(scope) {
  const input = isPlainObject(scope) ? scope : {};
  const global = isPlainObject(input.global) ? { ...input.global } : undefined;
  const projectsInput = isPlainObject(input.projects) ? input.projects : {};
  const projects = {};

  for (const [projectName, projectValue] of Object.entries(projectsInput)) {
    const project = isPlainObject(projectValue) ? projectValue : {};
    const jobsInput = isPlainObject(project.jobs) ? project.jobs : {};
    const jobs = {};

    for (const [jobName, jobValue] of Object.entries(jobsInput)) {
      jobs[jobName] = isPlainObject(jobValue) ? { ...jobValue } : {};
    }

    projects[projectName] = { ...project, jobs };
  }

  return {
    ...input,
    ...(global ? { global } : {}),
    projects,
  };
}

function getProject(scope, projectName) {
  if (!isPlainObject(scope.projects) || !isPlainObject(scope.projects[projectName])) {
    return undefined;
  }

  return scope.projects[projectName];
}

function getJob(project, jobName) {
  if (!isPlainObject(project) || !isPlainObject(project.jobs) || !isPlainObject(project.jobs[jobName])) {
    return undefined;
  }

  return project.jobs[jobName];
}

function resolveTier(scope, options = {}) {
  const projectName = options.project;
  const jobName = options.job;
  const defaultTier = options.defaultTier;
  const safeScope = isPlainObject(scope) ? scope : {};
  const project = getProject(safeScope, projectName);
  const job = getJob(project, jobName);

  if (typeof job?.tier === 'string' && job.tier.length > 0) {
    return { tier: job.tier, source: 'job', project: projectName, job: jobName };
  }

  if (typeof project?.tier === 'string' && project.tier.length > 0) {
    return { tier: project.tier, source: 'project', project: projectName, job: jobName };
  }

  if (typeof safeScope.global?.tier === 'string' && safeScope.global.tier.length > 0) {
    return { tier: safeScope.global.tier, source: 'global', project: projectName, job: jobName };
  }

  return { tier: defaultTier, source: 'default', project: projectName, job: jobName };
}

function promoteJobToProject(scope, options = {}) {
  const projectName = options.project;
  const jobName = options.job;
  const nextScope = cloneScope(scope);
  const resolved = resolveTier(nextScope, options);

  if (resolved.source === 'project') {
    return {
      promoted: false,
      reason: 'already-project',
      tier: resolved.tier,
      scope: nextScope,
    };
  }

  if (!isPlainObject(nextScope.projects)) {
    nextScope.projects = {};
  }

  if (!isPlainObject(nextScope.projects[projectName])) {
    nextScope.projects[projectName] = { jobs: {} };
  }

  const project = nextScope.projects[projectName];
  if (!isPlainObject(project.jobs)) {
    project.jobs = {};
  }

  project.tier = resolved.tier;

  const job = getJob(project, jobName);
  if (job && Object.prototype.hasOwnProperty.call(job, 'tier')) {
    delete job.tier;
  }

  return {
    promoted: true,
    tier: resolved.tier,
    source: resolved.source,
    scope: nextScope,
  };
}

module.exports = {
  resolveTier,
  promoteJobToProject,
};
