/**
 * `kasy deploy` — deploy backend.
 *
 * Detects which backend the project uses and runs the appropriate deploy:
 *
 *   Firebase  — detected via firebase.json
 *              Auto-detects project ID from .firebaserc.
 *              Uses existing gcloud authentication — no service account key needed.
 *
 *   Supabase  — detected via supabase/.temp/project-ref
 *              Deploys all edge functions, ensures FIREBASE_SERVICE_ACCOUNT_JSON
 *              secret is set (generates automatically via gcloud if missing),
 *              and shows APNs reminder.
 */

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 } = require('../utils/i18n');
const { getStoredLanguage } = require('../utils/license');
const { runDeploy: runFirebaseDeploy } = require('../scaffold/backends/firebase/deploy');
const { deployFunctions, setSupabaseSecrets, linkProject } = require('../scaffold/backends/supabase/deploy');
const { createFcmServiceAccountKey } = require('../scaffold/shared/fcm-service-account');

// ── Helpers ───────────────────────────────────────────────────────────────────

function printStep(ok, skipped, label, detail) {
  const text = `${label}${detail ? kleur.gray(` — ${detail.split('\n')[0]}`) : ''}`;
  if (ok) ui.log.success(text);
  else if (skipped) ui.log.message(kleur.dim(`– ${text}`));
  else ui.log.error(text);
}

/**
 * Read the Firebase project ID from android/app/google-services.json.
 * This file is always present in kasy-generated projects.
 */
async function readFirebaseProjectId(projectDir) {
  const gsPath = path.join(projectDir, 'android', 'app', 'google-services.json');
  if (!(await fs.pathExists(gsPath))) return null;
  try {
    const data = await fs.readJson(gsPath);
    return data?.project_info?.project_id || null;
  } catch {
    return null;
  }
}

/**
 * Read the linked Supabase project ref from supabase/.temp/project-ref.
 */
async function readSupabaseProjectRef(projectDir) {
  const refPath = path.join(projectDir, 'supabase', '.temp', 'project-ref');
  if (!(await fs.pathExists(refPath))) return null;
  try {
    return (await fs.readFile(refPath, 'utf8')).trim() || null;
  } catch {
    return null;
  }
}

/**
 * Check whether FIREBASE_SERVICE_ACCOUNT_JSON is already set in Supabase secrets.
 */
async function isServiceAccountJsonSet(projectDir) {
  const { exec } = require('node:child_process');
  const { promisify } = require('node:util');
  const execAsync = promisify(exec);
  try {
    const { stdout } = await execAsync('supabase secrets list', {
      cwd: projectDir,
      maxBuffer: 2 * 1024 * 1024,
    });
    return stdout.includes('FIREBASE_SERVICE_ACCOUNT_JSON');
  } catch {
    return false;
  }
}

// ── Firebase deploy ───────────────────────────────────────────────────────────

async function deployFirebase(projectDir, options, tr) {
  const cancel = () => { ui.cancel('Cancelled'); process.exit(0); };

  // Auto-detect Firebase Project ID
  let firebaseProjectId = options.project;
  if (!firebaseProjectId) {
    const rcPath = path.join(projectDir, '.firebaserc');
    if (await fs.pathExists(rcPath)) {
      try {
        const rc = await fs.readJson(rcPath);
        const detected = rc.projects?.default;
        if (detected) {
          firebaseProjectId = detected;
          ui.log.message(kleur.gray(`${tr('deploy.detected.project')} ${kleur.cyan(detected)}`));
        }
      } catch (_) {}
    }
  }
  if (!firebaseProjectId) {
    const pid = await ui.text({
      message: tr('deploy.q.project'),
      onCancel: cancel,
    });
    firebaseProjectId = String(pid || '').trim();
    if (!firebaseProjectId) process.exit(0);
  }

  // Read region — check kit_setup.json first, fall back to legacy .kasy/config.json
  let functionsRegion = 'us-central1';
  const kitSetupPath = path.join(projectDir, 'kit_setup.json');
  const legacyConfigPath = path.join(projectDir, '.kasy', 'config.json');
  for (const p of [kitSetupPath, legacyConfigPath]) {
    if (await fs.pathExists(p)) {
      try {
        const config = await fs.readJson(p);
        if (config.functionsRegion) { functionsRegion = config.functionsRegion; break; }
      } catch (_) {}
    }
  }

  const spinner = ui.timedSpinner();
  spinner.start(tr('deploy.firebase.spin'));
  let steps;
  try {
    steps = await runFirebaseDeploy(projectDir, null, firebaseProjectId, {
      functionsRegion,
      onProgress: (key) => { spinner.message(String(key)); },
    });
    spinner.stop(tr('deploy.firebase.spinDone'));
  } catch (err) {
    spinner.error(err.message);
    throw err;
  }

  if (steps?.length) {
    for (const s of steps) {
      printStep(s.ok, s.skipped, s.name, s.detail);
    }
  }

  // ── APNs reminder — required for iOS push notifications ──────────────────
  // Cannot be automated: the .p8 key only exists in Apple Developer Portal.
  const apnsBody = [
    kleur.yellow(tr('deploy.apns.title')),
    kleur.dim(tr('deploy.apns.step1')),
    kleur.dim(tr('deploy.apns.step2')),
    kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`),
  ].join('\n');
  ui.note(apnsBody);
}

// ── Supabase deploy ───────────────────────────────────────────────────────────

async function deploySupabase(projectDir, tr) {
  // ── 1. Get project ref ──────────────────────────────────────────────────
  const projectRef = await readSupabaseProjectRef(projectDir);
  if (!projectRef) {
    ui.log.error(tr('deploy.supabase.notLinked'));
    ui.log.message(kleur.gray(tr('deploy.supabase.linkHint')));
    process.exit(1);
  }
  ui.log.message(kleur.gray(tr('deploy.supabase.projectRef', { ref: kleur.cyan(projectRef) })));

  // ── 2. FCM Service Account JSON ─────────────────────────────────────────
  const alreadySet = await isServiceAccountJsonSet(projectDir);
  if (alreadySet) {
    printStep(true, false, tr('deploy.supabase.sakAlready'));
  } else {
    const firebaseProjectId = await readFirebaseProjectId(projectDir);

    if (firebaseProjectId) {
      const fcmSpinner = ui.timedSpinner();
      fcmSpinner.start(tr('deploy.supabase.sakSpin'));
      const fcmResult = await createFcmServiceAccountKey(firebaseProjectId);
      fcmSpinner.stop(tr('deploy.supabase.sakSpinDone'));

      if (fcmResult.ok) {
        const secretSteps = await setSupabaseSecrets(projectDir, {
          firebaseProjectId,
          firebaseServiceAccountJson: fcmResult.json,
        });
        for (const s of secretSteps) printStep(s.ok, false, s.name, s.error);
      } else {
        printStep(false, false, 'FIREBASE_SERVICE_ACCOUNT_JSON', fcmResult.error);
        ui.log.warn(tr('deploy.supabase.sakManual'));
      }
    } else {
      printStep(false, false, 'FIREBASE_SERVICE_ACCOUNT_JSON', tr('deploy.supabase.sakNoGS'));
    }
  }

  // ── 3. Deploy edge functions ────────────────────────────────────────────
  const fnSpinner = ui.timedSpinner();
  fnSpinner.start(tr('deploy.supabase.fnSpin'));
  const fnResult = await deployFunctions(projectDir);
  fnSpinner.stop(tr('deploy.supabase.fnSpinDone'));

  if (Array.isArray(fnResult)) {
    fnResult.forEach((s) => printStep(s.ok, s.skipped, s.name, s.error));
  } else if (fnResult.skipped) {
    printStep(true, true, tr('deploy.supabase.fnNone'));
  } else {
    printStep(fnResult.ok, false, 'supabase functions deploy', fnResult.error);
  }

  // ── 4. APNs reminder ────────────────────────────────────────────────────
  const firebaseProjectId = await readFirebaseProjectId(projectDir);
  const apnsLines = [
    kleur.yellow(tr('deploy.apns.title')),
    kleur.dim(tr('deploy.apns.step1')),
    kleur.dim(tr('deploy.apns.step2')),
  ];
  if (firebaseProjectId) {
    apnsLines.push(kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`));
  }
  ui.note(apnsLines.join('\n'));
}

// ── Entry point ───────────────────────────────────────────────────────────────

/**
 * @param {string} directory - project directory (default: cwd)
 * @param {object} options
 * @param {string} [options.project] - Firebase Project ID (overrides auto-detect, Firebase only)
 * @param {object} ctx
 * @param {string} [ctx.language]
 */
async function runDeployCommand(directory, options = {}, { language: langHint } = {}) {
  const language = langHint || getStoredLanguage() || 'en';
  const tr = createTranslator(language);

  const projectDir = path.resolve(directory || '.');

  const isFirebase  = await fs.pathExists(path.join(projectDir, 'firebase.json'));
  const isSupabase  = await fs.pathExists(path.join(projectDir, 'supabase'));

  if (isFirebase) {
    printCompactHeader(tr);
    ui.intro(tr('deploy.firebase.intro'));
    await deployFirebase(projectDir, options, tr);
    ui.outro(tr('deploy.outro'));
    return;
  }

  if (isSupabase) {
    printCompactHeader(tr);
    ui.intro(tr('deploy.supabase.intro'));
    await deploySupabase(projectDir, tr);
    ui.outro(tr('deploy.outro'));
    return;
  }

  ui.log.error(tr('deploy.error.notProject'));
  process.exit(1);
}

module.exports = { runDeployCommand };
