'use strict';

const path = require('node:path');
const fs = require('fs-extra');
const kleur = require('kleur');
const ui = require('../utils/ui');
const { printCompactHeader } = require('../utils/brand');
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
const {
  isKasyFlutterProject,
  readBundleId,
  applePrivateKeyPath,
  validateAppleSetup,
  writeAppleEnv,
  installPrivateKey,
  openUrl,
  iosReleaseDocPath,
  runReleaseScript,
  checkIosSigning,
  checkDiskSpaceForIosBuild,
  isXcodeCacheBuildError,
  isPodNetworkError,
  printBuildFailureHints,
  printPodNetworkHints,
  runIosClean,
  MIN_DISK_GB_FOR_IOS_BUILD,
  URL_APP_STORE_CONNECT_APPS,
  URL_APP_STORE_CONNECT_API,
} = require('../utils/apple-release');
const { validateGoogleIosUrlScheme } = require('../scaffold/shared/post-build');

async function assertProject(projectDir, t) {
  if (!(await isKasyFlutterProject(projectDir))) {
    throw new Error(t('ios.error.notProject'));
  }
}

async function runConfigure(directory, options = {}) {
  const t = createTranslator(options.language || detectDefaultLanguage());
  const projectDir = path.resolve(directory || '.');

  await assertProject(projectDir, t);

  const bundleId = await readBundleId(projectDir);
  printCompactHeader(t);
  ui.intro(t('ios.configure.title'));

  if (bundleId) {
    ui.log.info(`${t('ios.configure.bundleId')}: ${kleur.cyan(bundleId)}`);
  }
  ui.log.message(kleur.dim(`${t('ios.configure.doc')}: ${iosReleaseDocPath(options.language || detectDefaultLanguage())}`));

  ui.log.info(t('ios.configure.openingLinks'));
  openUrl(URL_APP_STORE_CONNECT_API);
  openUrl(URL_APP_STORE_CONNECT_APPS);

  ui.note(t('ios.configure.note.body'), t('ios.configure.note.title'));

  const cancel = () => { ui.cancel(t('ios.configure.cancelled')); process.exit(0); };
  const required = (v) => (v && String(v).trim().length > 0 ? undefined : t('ios.configure.q.required'));

  const apiKeyRaw = await ui.text({
    message: t('ios.configure.q.apiKey'),
    validate: required,
    onCancel: cancel,
  });
  const issuerIdRaw = await ui.text({
    message: t('ios.configure.q.issuerId'),
    validate: required,
    onCancel: cancel,
  });
  const p8PathRaw = await ui.text({
    message: t('ios.configure.q.p8Path'),
    validate: async (v) => {
      if (!v || !v.trim()) return t('ios.configure.q.required');
      const resolved = path.resolve(v.trim().replace(/^~/, process.env.HOME || ''));
      if (!(await fs.pathExists(resolved))) return t('ios.configure.q.p8NotFound');
      return undefined;
    },
    onCancel: cancel,
  });
  const appIdRaw = await ui.text({
    message: t('ios.configure.q.appId'),
    initialValue: '',
    onCancel: cancel,
  });

  const apiKey = apiKeyRaw.trim();
  const issuerId = issuerIdRaw.trim();
  const p8Source = path.resolve(p8PathRaw.trim().replace(/^~/, process.env.HOME || ''));

  const destPath = await installPrivateKey(p8Source, apiKey);
  await writeAppleEnv(projectDir, {
    apiKey,
    issuerId,
    appId: appIdRaw?.trim() || '',
  });

  ui.log.success(t('ios.configure.success'));
  ui.log.message(kleur.dim(`${t('ios.configure.p8Installed')}: ${destPath}`));
  ui.outro(kleur.cyan(`${t('ios.configure.next')}: kasy ios release`));
}

async function runBuildOrRelease(directory, options = {}, mode) {
  const t = createTranslator(options.language || detectDefaultLanguage());
  const projectDir = path.resolve(directory || '.');

  await assertProject(projectDir, t);

  if (mode === 'release' && process.platform !== 'darwin') {
    printCompactHeader(t);
    ui.log.warn(t('ios.error.notMac'));
    ui.log.info(`${t('ios.error.useCodemagic')}: kasy codemagic configure`);
    process.exitCode = 1;
    return;
  }

  if (process.platform === 'darwin') {
    const signing = await checkIosSigning(projectDir);
    if (!signing.ok) {
      printCompactHeader(t);
      ui.log.warn(t('ios.error.signing'));
      ui.log.message(kleur.dim(t('ios.error.signingHint')));
      process.exitCode = 1;
      return;
    }
  }

  if (mode === 'release') {
    const validation = await validateAppleSetup(projectDir);
    if (!validation.ok) {
      printCompactHeader(t);
      ui.log.warn(t('ios.error.notConfigured'));
      const shouldConfigure = await ui.confirm({
        message: t('ios.release.askConfigure'),
        initialValue: true,
      });
      if (!shouldConfigure) {
        if (validation.issues.includes('missing_env')) {
          ui.log.message(kleur.dim(t('ios.error.runConfigure')));
        }
        process.exitCode = 1;
        return;
      }
      await runConfigure(directory, options);
      const recheck = await validateAppleSetup(projectDir);
      if (!recheck.ok) {
        ui.log.error(t('ios.error.notConfigured'));
        process.exitCode = 1;
        return;
      }
    }
  }

  const googleScheme = await validateGoogleIosUrlScheme(projectDir);
  if (!googleScheme.ok) {
    printCompactHeader(t);
    ui.log.error(t('ios.error.googleUrlScheme'));
    ui.log.message(kleur.dim(googleScheme.error));
    ui.log.info(t('ios.error.googleUrlSchemeHint'));
    process.exitCode = 1;
    return;
  }

  const args = [];
  if (options.noBump) args.push('--no-bump');
  if (options.versionName) args.push('--version-name', options.versionName);
  if (mode === 'build') args.push('--no-upload');

  if (process.platform === 'darwin') {
    const disk = await checkDiskSpaceForIosBuild(projectDir);
    if (!disk.ok && disk.freeGb !== null) {
      ui.log.warn(t('ios.warn.lowDisk', { gb: disk.freeGb, min: MIN_DISK_GB_FOR_IOS_BUILD }));
    }
  }

  printCompactHeader(t);
  ui.intro(mode === 'build' ? t('ios.build.title') : t('ios.release.title'));

  try {
    await runReleaseScript(projectDir, args, t);
    ui.outro(mode === 'build' ? t('ios.build.success') : t('ios.release.success'));
  } catch (err) {
    const output = err.buildOutput || err.message;
    if (isPodNetworkError(output)) {
      printPodNetworkHints(t);
    } else if (isXcodeCacheBuildError(output)) {
      ui.log.error(output.slice(-4000));
      printBuildFailureHints(t, projectDir);
    } else {
      ui.log.error(output.slice(-4000));
    }
    process.exitCode = 1;
  }
}

async function runClean(directory, options = {}) {
  const t = createTranslator(options.language || detectDefaultLanguage());
  const projectDir = path.resolve(directory || '.');

  await assertProject(projectDir, t);

  if (process.platform !== 'darwin') {
    printCompactHeader(t);
    ui.log.warn(t('ios.clean.notMac'));
    process.exitCode = 1;
    return;
  }

  printCompactHeader(t);
  ui.intro(t('ios.clean.title'));
  try {
    await runIosClean(projectDir, t);
    ui.log.success(t('ios.clean.success'));
    ui.outro(kleur.cyan(`${t('ios.configure.next')}: kasy ios release`));
  } catch (err) {
    ui.log.error(err.message);
    process.exitCode = 1;
  }
}

module.exports = {
  runConfigure,
  runBuild: (dir, opts) => runBuildOrRelease(dir, opts, 'build'),
  runRelease: (dir, opts) => runBuildOrRelease(dir, opts, 'release'),
  runClean,
};
