'use strict';

/**
 * ghostPublisher (Session 63 / A1-S4d) — saves DRAFTS to the self-hosted
 * Ghost instance. DRAFTS ONLY — nothing anywhere auto-posts; Kev publishes.
 *
 * Zero new dependencies: the Ghost Admin API JWT is HS256 built with node
 * crypto. Env-gated (GHOST_URL + GHOST_ADMIN_API_KEY 'id:secret') — without
 * env every call is a documented no-op.
 */

const crypto = require('crypto');

const b64url = (buf) => Buffer.from(buf).toString('base64url');

/** Ghost Admin API JWT: HS256, kid = key id, aud '/admin/', 5-min expiry. */
function ghostJwt(adminKey, nowSec = Math.floor(Date.now() / 1000)) {
  const [id, secret] = String(adminKey || '').split(':');
  if (!id || !secret) return null;
  const header = b64url(JSON.stringify({ alg: 'HS256', typ: 'JWT', kid: id }));
  const payload = b64url(JSON.stringify({ iat: nowSec, exp: nowSec + 300, aud: '/admin/' }));
  const sig = crypto.createHmac('sha256', Buffer.from(secret, 'hex'))
    .update(`${header}.${payload}`).digest('base64url');
  return `${header}.${payload}.${sig}`;
}

function isConfigured() {
  return Boolean(process.env.GHOST_URL && process.env.GHOST_ADMIN_API_KEY);
}

/** Save one draft. Returns { ok, id? } — never throws. */
async function saveDraft({ title, html, tags = [] }, opts = {}) {
  if (!opts.force && !isConfigured()) return { ok: false, reason: 'ghost not configured' };
  const fetchImpl = opts.fetchImpl || fetch;
  const base = (opts.url || process.env.GHOST_URL || '').replace(/\/$/, '');
  const token = ghostJwt(opts.adminKey || process.env.GHOST_ADMIN_API_KEY, opts.nowSec);
  if (!token) return { ok: false, reason: 'bad admin key' };
  try {
    const res = await fetchImpl(`${base}/ghost/api/admin/posts/?source=html`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Authorization: `Ghost ${token}` },
      body: JSON.stringify({ posts: [{ title, html, status: 'draft', tags }] }),
    });
    if (!res.ok) return { ok: false, reason: `ghost ${res.status}` };
    const data = await res.json().catch(() => ({}));
    return { ok: true, id: data.posts && data.posts[0] && data.posts[0].id };
  } catch (e) {
    return { ok: false, reason: e.message };
  }
}

/** Daily slate preview + weekly record review drafts from the desk pack. */
async function saveDailyDrafts(pack, opts = {}) {
  if (!pack || !pack.formats) return { ok: false, reason: 'no pack' };
  const results = [];
  const wire = pack.formats.morning_wire && pack.formats.morning_wire[0];
  if (wire) {
    results.push(await saveDraft({
      title: `The Slate — ${new Date(pack.generated_at).toDateString()}`,
      html: `<pre>${escapeHtml(wire.text)}</pre>`,
      tags: ['slate'],
    }, opts));
  }
  const settle = pack.formats.settle && pack.formats.settle[0];
  if (settle) {
    results.push(await saveDraft({
      title: `The Settle — ${new Date(pack.generated_at).toDateString()}`,
      html: `<pre>${escapeHtml(settle.text)}</pre>`,
      tags: ['settle'],
    }, opts));
  }
  return { ok: results.every((r) => r.ok), results };
}

const escapeHtml = (s) => String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

module.exports = { saveDraft, saveDailyDrafts, ghostJwt, isConfigured };
