const path = require('node:path');
const fs = require('fs-extra');
const { exec } = require('node:child_process');
const { promisify } = require('node:util');
const kleur = require('kleur');
const ui = require('../utils/ui');
const { printCompactHeader } = require('../utils/brand');
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
const { inspectPng } = require('./splash');
const {
  writeAndroidAdaptiveBackground,
  writeTransparentSquare,
} = require('../utils/png-padding');

const execAsync = promisify(exec);

const ASSETS_DIR = path.join('assets', 'images');
const ICON_NAME = 'icon.png';
const ANDROID_BG_NAME = 'icon_android.png';
const ANDROID_FG_EMPTY_NAME = 'icon_foreground_empty.png';

async function assertKasyProject(projectDir, t) {
  const kitSetupPath = path.join(projectDir, 'kit_setup.json');
  const pubspecPath = path.join(projectDir, 'pubspec.yaml');
  if (!(await fs.pathExists(kitSetupPath)) && !(await fs.pathExists(pubspecPath))) {
    throw new Error(t('icon.error.notKasyProject'));
  }
  const assetsDir = path.join(projectDir, ASSETS_DIR);
  await fs.ensureDir(assetsDir);
}

function resolveInputPath(flagValue) {
  if (!flagValue) return null;
  const expanded = flagValue.startsWith('~')
    ? path.join(require('node:os').homedir(), flagValue.slice(1))
    : flagValue;
  return path.resolve(expanded);
}

async function runIcon(projectDir, options = {}) {
  const language = options.language || detectDefaultLanguage();
  const t = createTranslator(language);

  printCompactHeader();
  ui.intro(kleur.bold().cyan(t('icon.intro')));

  await assertKasyProject(projectDir, t);

  const imagePath = resolveInputPath(options.image);

  if (!imagePath) {
    ui.log.error(t('icon.error.imageRequired'));
    ui.log.message(kleur.dim('kasy icon --image <icon.png>'));
    process.exit(1);
  }

  if (!(await fs.pathExists(imagePath))) {
    ui.log.error(t('icon.error.fileNotFound', { path: imagePath }));
    process.exit(1);
  }

  const inspectSpinner = ui.spinner();
  inspectSpinner.start(t('icon.validating'));

  let info;
  try {
    info = await inspectPng(imagePath);
  } catch (err) {
    inspectSpinner.stop(`✖ ${err.message || t('icon.error.notPng')}`);
    process.exit(1);
  }

  if (!info.valid) {
    inspectSpinner.stop(`✖ ${t('icon.error.notPng')}`);
    process.exit(1);
  }

  inspectSpinner.stop(t('icon.validated'));

  const warnings = [];
  if (info.width !== info.height) {
    warnings.push(t('icon.warn.notSquare', { w: info.width, h: info.height }));
  }
  if (info.width < 1024 || info.height < 1024) {
    warnings.push(t('icon.warn.small', { w: info.width, h: info.height }));
  }
  if (info.hasAlpha) {
    warnings.push(t('icon.warn.hasAlpha'));
  }
  if (warnings.length > 0) {
    ui.note(warnings.map((w) => `${kleur.yellow('⚠')} ${w}`).join('\n'), t('icon.warn.title'));
  }

  const assetsDir = path.join(projectDir, ASSETS_DIR);
  const dest = path.join(assetsDir, ICON_NAME);
  const androidBgDest = path.join(assetsDir, ANDROID_BG_NAME);
  const androidFgEmptyDest = path.join(assetsDir, ANDROID_FG_EMPTY_NAME);

  const copySpinner = ui.spinner();
  copySpinner.start(t('icon.copying'));
  await fs.copy(imagePath, dest, { overwrite: true });
  copySpinner.stop(t('icon.copied'));

  const adaptiveSpinner = ui.spinner();
  adaptiveSpinner.start(t('icon.adaptive.generating'));
  let adaptiveInfo;
  try {
    adaptiveInfo = await writeAndroidAdaptiveBackground(dest, androidBgDest);
    if (!(await fs.pathExists(androidFgEmptyDest))) {
      await writeTransparentSquare(androidFgEmptyDest);
    }
    adaptiveSpinner.stop(t('icon.adaptive.generated'));
  } catch (err) {
    adaptiveSpinner.stop(`⚠ ${t('icon.adaptive.failed')}`);
    ui.log.message(kleur.dim(err.message || String(err)));
    process.exit(1);
  }

  if (!adaptiveInfo.color.sampled) {
    ui.note(t('icon.adaptive.fallbackColor'), t('icon.adaptive.fallbackTitle'));
  }

  if (options.skipGenerate) {
    ui.note(t('icon.skipGenerate.hint'), t('icon.skipGenerate.title'));
    ui.outro(t('icon.done'));
    return;
  }

  const genSpinner = ui.spinner();
  genSpinner.start(t('icon.generating'));
  const result = await runFlutterLauncherIcons(projectDir);
  if (result.ok) {
    genSpinner.stop(t('icon.generated'));
  } else {
    genSpinner.stop(`⚠ ${t('icon.error.generateFailed')}`);
    if (result.stderr) {
      ui.log.message(kleur.dim(result.stderr.split('\n').slice(0, 8).join('\n')));
    }
    ui.log.message(kleur.dim('dart run flutter_launcher_icons'));
    process.exit(1);
  }

  const summary = `${kleur.bold(t('icon.summary.icon'))}: ${kleur.white(ICON_NAME)} (${info.width}x${info.height})`;
  ui.note(summary, t('icon.summary.title'));
  ui.note(t('icon.reinstall.hint'), t('icon.reinstall.title'));

  ui.outro(t('icon.done'));
}

async function runFlutterLauncherIcons(projectDir) {
  try {
    const { stdout, stderr } = await execAsync(
      'dart run flutter_launcher_icons',
      {
        cwd: projectDir,
        maxBuffer: 16 * 1024 * 1024,
        timeout: 240_000,
      },
    );
    return { ok: true, stdout, stderr };
  } catch (err) {
    return {
      ok: false,
      error: err.message,
      stdout: err.stdout || '',
      stderr: err.stderr || '',
    };
  }
}

module.exports = { runIcon, runFlutterLauncherIcons };
