/**
 * `kasy check` — push notifications diagnostic.
 *
 * Verifies whether the push notification stack is correctly configured
 * for the current project (Supabase backend only — Firebase uses ADC automatically).
 *
 * Checks:
 *   1. Project is linked (supabase/.temp/project-ref exists)
 *   2. FIREBASE_SERVICE_ACCOUNT_JSON secret is set
 *   3. FIREBASE_PROJECT_ID secret is set
 *   4. Edge function send-push-notification is deployed
 *
 * Auto-fix (--fix flag):
 *   Generates FIREBASE_SERVICE_ACCOUNT_JSON automatically via gcloud and sets it.
 */

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 { exec } = require('node:child_process');
const { promisify } = require('node:util');

const { getStoredLanguage } = require('../utils/license');
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
const { createFcmServiceAccountKey } = require('../scaffold/shared/fcm-service-account');
const { setSupabaseSecrets } = require('../scaffold/backends/supabase/deploy');

const execAsync = promisify(exec);

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

async function runCmd(cmd, cwd) {
  try {
    const { stdout } = await execAsync(cmd, { cwd, maxBuffer: 2 * 1024 * 1024 });
    return { ok: true, stdout: stdout.trim() };
  } catch (err) {
    return { ok: false, error: err.message, stdout: (err.stdout || '').trim() };
  }
}

function ok(label, detail)   { ui.log.success(`${label}${detail ? kleur.gray(` — ${detail}`) : ''}`); }
function fail(label, detail) { ui.log.error(`${label}${detail ? kleur.gray(` — ${detail}`) : ''}`); }
function warn(label, detail) { ui.log.warn(`${label}${detail ? kleur.gray(` — ${detail}`) : ''}`); }
function info(label)         { ui.log.message(kleur.dim(`– ${label}`)); }

/**
 * Read the linked Supabase project ref.
 */
async function readProjectRef(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; }
}

/**
 * Read Firebase project ID from android/app/google-services.json.
 */
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; }
}

/**
 * List Supabase secrets names (not values) for the linked project.
 * Returns a Set of secret names, or null if the command fails.
 */
async function listSecretNames(projectDir) {
  const result = await runCmd('supabase secrets list', projectDir);
  if (!result.ok) return null;
  const names = new Set();
  for (const line of result.stdout.split('\n')) {
    const name = line.trim().split(/\s+/)[0];
    if (name && name !== 'Name' && name !== '---') names.add(name);
  }
  return names;
}

/**
 * List deployed Supabase function names.
 * Returns a Set of function names, or null if the command fails.
 */
async function listDeployedFunctions(projectDir) {
  const result = await runCmd('supabase functions list', projectDir);
  if (!result.ok) return null;
  const names = new Set();
  for (const line of result.stdout.split('\n')) {
    const parts = line.trim().split(/\s+/);
    if (parts[0] && parts[0] !== 'Name' && parts[0] !== '---') names.add(parts[0]);
  }
  return names;
}

// ── Main ──────────────────────────────────────────────────────────────────────

/**
 * @param {object} options
 * @param {string}  [options.directory] - project directory (default: cwd)
 * @param {boolean} [options.fix]       - auto-fix missing configuration
 * @param {string}  [options.language]
 */
async function runCheck(options = {}) {
  const projectDir = path.resolve(options.directory || '.');
  const lang = options.language || getStoredLanguage() || detectDefaultLanguage();
  const t = createTranslator(lang);

  printCompactHeader(t);
  ui.intro(t('check.intro'));

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

  if (isFirebase && !isSupabase) {
    ok(t('check.firebase.detected'));
    info(t('check.firebase.adcInfo'));
    const firebaseProjectId = await readFirebaseProjectId(projectDir);
    const apnsLines = [
      kleur.yellow(t('check.apns.warn')),
      kleur.dim(t('check.apns.where')),
    ];
    if (firebaseProjectId) {
      apnsLines.push(kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`));
    }
    ui.note(apnsLines.join('\n'));
    ui.outro(t('check.done'));
    return;
  }

  if (!isSupabase) {
    ui.log.error(t('check.notKasy'));
    ui.cancel(t('check.aborted'));
    process.exit(1);
  }

  // ── 1. Project linked? ────────────────────────────────────────────────────
  const projectRef = await readProjectRef(projectDir);
  if (!projectRef) {
    fail(t('check.supabase.notLinked'), t('check.supabase.notLinkedHint'));
    ui.cancel(t('check.aborted'));
    process.exit(1);
  }
  ok(t('check.supabase.linked'), projectRef);

  // ── Read secrets list ─────────────────────────────────────────────────────
  const spinner = ui.spinner();
  spinner.start(t('check.spin.secrets'));
  const secrets = await listSecretNames(projectDir);
  spinner.stop(t('check.spin.secretsDone'));

  if (!secrets) {
    warn(t('check.secrets.listFailed'), t('check.secrets.checkLogin'));
  }

  // ── 2. FIREBASE_PROJECT_ID ────────────────────────────────────────────────
  const firebaseProjectId = await readFirebaseProjectId(projectDir);
  if (secrets) {
    if (secrets.has('FIREBASE_PROJECT_ID')) {
      ok(t('check.fbProjId.ok'));
    } else {
      fail(t('check.fbProjId.missing'));
      if (firebaseProjectId) {
        ui.log.message(kleur.gray(t('check.fbProjId.fixHint', { id: firebaseProjectId })));
        if (options.fix) {
          const r = await runCmd(`supabase secrets set FIREBASE_PROJECT_ID="${firebaseProjectId}"`, projectDir);
          r.ok
            ? ok(t('check.fbProjId.fixed'))
            : fail(t('check.fbProjId.fixFailed'), r.error);
        }
      }
    }
  }

  // ── 3. FIREBASE_SERVICE_ACCOUNT_JSON ─────────────────────────────────────
  if (secrets) {
    if (secrets.has('FIREBASE_SERVICE_ACCOUNT_JSON')) {
      ok(t('check.fbSak.ok'));
    } else {
      fail(t('check.fbSak.missing'));

      if (options.fix && firebaseProjectId) {
        const fixSpinner = ui.spinner();
        fixSpinner.start(t('check.fbSak.spin'));
        const fcmResult = await createFcmServiceAccountKey(firebaseProjectId);
        fixSpinner.stop(t('check.fbSak.spinDone'));

        if (fcmResult.ok) {
          const secretSteps = await setSupabaseSecrets(projectDir, {
            firebaseProjectId,
            firebaseServiceAccountJson: fcmResult.json,
          });
          const setStep = secretSteps.find((s) => s.name === 'secret FIREBASE_SERVICE_ACCOUNT_JSON');
          setStep?.ok
            ? ok(t('check.fbSak.fixed'))
            : fail(t('check.fbSak.fixFailed'), setStep?.error);
        } else {
          fail(t('check.fbSak.genFailed'), fcmResult.error);
          ui.log.message(kleur.gray(t('check.fbSak.manual')));
        }
      } else {
        ui.log.message(kleur.gray(t('check.fbSak.hint')));
      }
    }
  }

  // ── 4. Edge function send-push-notification ────────────────────────────────
  const fnSpinner = ui.spinner();
  fnSpinner.start(t('check.fn.spin'));
  const functions = await listDeployedFunctions(projectDir);
  fnSpinner.stop(t('check.fn.spinDone'));

  if (!functions) {
    warn(t('check.fn.listFailed'), t('check.secrets.checkLogin'));
  } else if (functions.has('send-push-notification')) {
    ok(t('check.fn.deployed'));
  } else {
    fail(t('check.fn.missing'));
    if (options.fix) {
      const deploySpinner = ui.spinner();
      deploySpinner.start(t('check.fn.deploySpin'));
      const r = await runCmd('supabase functions deploy send-push-notification', projectDir);
      r.ok
        ? deploySpinner.stop(t('check.fn.deployDone'))
        : deploySpinner.error(`${t('check.fn.deployFailed')}${r.error ? ` — ${r.error}` : ''}`);
    } else {
      ui.log.message(kleur.gray(t('check.fn.hint')));
    }
  }

  // ── 5. APNs reminder ─────────────────────────────────────────────────────
  const apnsLines = [
    kleur.yellow(t('check.apns.warn')),
    kleur.dim(t('check.apns.where')),
  ];
  if (firebaseProjectId) {
    apnsLines.push(kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`));
  }
  ui.note(apnsLines.join('\n'));
  ui.outro(t('check.done'));
}

module.exports = { runCheck };
