/**
 * Otomasyum – Shopify entegrasyon örneği (Node.js / App Backend) v2.1.0
 *
 * İki bağımsız modül:
 *
 *  1. notifyOtomasyum()     → Shopify'dan Otomasyum Sync API'ye olay
 *  2. contentApiGet()       → Otomasyum Content API (bellek cache + stale)
 *  3. publishArticle()      → Panel blogunu Shopify Blog Article olarak push (opsiyonel)
 *
 * Ortam (.env):
 *   OTOMASYUM_API_BASE          = https://www.otomasyum.com
 *   OTOMASYUM_SYNC_URL          = (opsiyonel) tam Sync URL
 *   OTOMASYUM_API_KEY           = panel Webhook API anahtarı
 *   OTOMASYUM_CONTENT_URL       = (opsiyonel) Content API kökü
 *   OTOMASYUM_CONTENT_TOKEN     = panel Content API token
 *   OTOMASYUM_SITE_URL          = https://magaza.com (Referer / Origin allowlist)
 *   OTOMASYUM_CACHE_TTL_MS      = 300000
 *   OTOMASYUM_CACHE_CLEAR_SECRET= cache-clear endpoint sırrı
 *   SHOPIFY_SHOP                = magaza.myshopify.com
 *   SHOPIFY_ADMIN_TOKEN         = shpat_...
 *   SHOPIFY_BLOG_ID             = 123456789
 *   SHOPIFY_API_VERSION         = 2024-10
 *   SHOPIFY_WEBHOOK_SECRET      = Shopify app webhook HMAC secret
 *
 * CommonJS (require). ESM için: import createRequire veya bu dosyayı .mjs'e taşıyın.
 */

'use strict';

const crypto = require('crypto');

const VERSION = '2.1.0';
const API_BASE = (process.env.OTOMASYUM_API_BASE || 'https://www.otomasyum.com').replace(/\/$/, '');
const SYNC_URL = process.env.OTOMASYUM_SYNC_URL
  || `${API_BASE}/api/v1/tenant/sites/sync`;
const API_KEY = process.env.OTOMASYUM_API_KEY || 'YOUR_WEBHOOK_API_KEY';
const CONTENT_BASE = (process.env.OTOMASYUM_CONTENT_URL || `${API_BASE}/api/v1/content`).replace(/\/$/, '');
const CONTENT_TOKEN = process.env.OTOMASYUM_CONTENT_TOKEN || 'YOUR_CONTENT_TOKEN';
const SITE_URL = (process.env.OTOMASYUM_SITE_URL || '').replace(/\/$/, '');
const CACHE_TTL_MS = parseInt(process.env.OTOMASYUM_CACHE_TTL_MS || '300000', 10);
const SHOPIFY_SHOP = (process.env.SHOPIFY_SHOP || '').replace(/^https?:\/\//i, '').replace(/\/$/, '');
const SHOPIFY_ADMIN_TOKEN = process.env.SHOPIFY_ADMIN_TOKEN || '';
const SHOPIFY_BLOG_ID = process.env.SHOPIFY_BLOG_ID || '';
const SHOPIFY_API_VERSION = process.env.SHOPIFY_API_VERSION || '2024-10';

/**
 * Shopify webhook topic → Sync action
 * (SiteSyncController aynı map'i legacy event için sunucuda da uygular.)
 */
const SHOPIFY_TOPIC_ACTIONS = {
  'orders/create': 'order_created',
  'orders/updated': 'order_updated',
  'products/create': 'content_updated',
  'products/update': 'content_updated',
  'products/delete': 'content_updated',
  'customers/create': 'customer_created',
  'customers/update': 'customer_updated',
  'app/uninstalled': 'app_uninstalled',
};

function mapShopifyTopicToAction(topic) {
  if (!topic || typeof topic !== 'string') {
    return 'content_updated';
  }
  return SHOPIFY_TOPIC_ACTIONS[topic] || topic.replace(/\//g, '_');
}

/**
 * Shopify webhook HMAC doğrulama (X-Shopify-Hmac-Sha256).
 * @param {string|Buffer} rawBody  Ham istek gövdesi (JSON.stringify değil)
 * @param {string} hmacHeader
 * @param {string} [secret]
 * @returns {boolean}
 */
function verifyShopifyWebhookHmac(rawBody, hmacHeader, secret = process.env.SHOPIFY_WEBHOOK_SECRET) {
  if (!secret || !hmacHeader) {
    return false;
  }
  const digest = crypto
    .createHmac('sha256', secret)
    .update(rawBody, Buffer.isBuffer(rawBody) ? undefined : 'utf8')
    .digest('base64');
  const a = Buffer.from(digest);
  const b = Buffer.from(String(hmacHeader));
  if (a.length !== b.length) {
    return false;
  }
  return crypto.timingSafeEqual(a, b);
}

/**
 * Otomasyum Sync API'ye olay gönderir (throw etmez).
 *
 * @param {string} topicOrAction  Shopify topic (orders/create) veya Sync action
 * @param {object} fields         Kök seviye alanlar (id, title, ...)
 * @param {string} shop           magaza.myshopify.com
 * @param {object} [opts]
 * @param {string} [opts.idempotencyKey]
 */
async function notifyOtomasyum(topicOrAction, fields, shop, opts = {}) {
  const action = mapShopifyTopicToAction(topicOrAction);
  const siteUrl = shop.startsWith('http') ? shop : `https://${shop}`;
  const body = {
    action,
    source: 'shopify',
    shop,
    site_url: siteUrl,
    sent_at: new Date().toISOString(),
    ...(fields && typeof fields === 'object' ? fields : {}),
  };

  const idempotencyKey = opts.idempotencyKey
    || crypto.createHash('sha256')
      .update(`${action}|${shop}|${JSON.stringify(fields || {})}`)
      .digest('hex');

  try {
    const response = await fetch(SYNC_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': API_KEY,
        'X-Site-URL': siteUrl,
        'X-Idempotency-Key': idempotencyKey,
        'X-Event': topicOrAction,
        'User-Agent': `OtomasyumShopify/${VERSION}`,
      },
      body: JSON.stringify(body),
      signal: AbortSignal.timeout(10_000),
    });

    if (!response.ok) {
      const text = await response.text().catch(() => '');
      console.error('[Otomasyum] Sync failed:', response.status, text);
    }

    return response;
  } catch (err) {
    console.error('[Otomasyum] Sync error:', err.message);
    return null;
  }
}

/**
 * Express/Shopify webhook handler fabrikası.
 * rawBody middleware gerekir: app.use(express.json({ verify: (req,res,buf)=>{ req.rawBody = buf; }}))
 *
 * @param {string} topic  örn. 'orders/create'
 */
function createShopifyWebhookHandler(topic) {
  return async (req, res) => {
    const hmac = req.get('X-Shopify-Hmac-Sha256') || '';
    const raw = req.rawBody || Buffer.from(JSON.stringify(req.body || {}));
    if (process.env.SHOPIFY_WEBHOOK_SECRET && !verifyShopifyWebhookHmac(raw, hmac)) {
      return res.status(401).send('Invalid HMAC');
    }

    const shop = req.get('X-Shopify-Shop-Domain') || '';
    const payload = req.body || {};
    await notifyOtomasyum(topic, {
      id: payload.id,
      title: payload.title || payload.name || undefined,
      email: payload.email || undefined,
      total_price: payload.total_price || undefined,
    }, shop, {
      idempotencyKey: req.get('X-Shopify-Webhook-Id') || undefined,
    });

    return res.status(200).send('OK');
  };
}

exports.ordersCreate = createShopifyWebhookHandler('orders/create');
exports.productsUpdate = createShopifyWebhookHandler('products/update');

// ============================================================
// CONTENT API
// ============================================================

const _contentCache = new Map();

/**
 * @param {string} endpoint
 * @param {{ ttlMs?: number, userIp?: string }} [opts]
 * @returns {Promise<object|null>}
 */
async function contentApiGet(endpoint, opts = {}) {
  const ttlMs = opts.ttlMs ?? CACHE_TTL_MS;
  const userIp = opts.userIp || '0.0.0.0';
  const url = `${CONTENT_BASE}/${CONTENT_TOKEN}/${endpoint.replace(/^\//, '')}`;
  const now = Date.now();
  const cached = _contentCache.get(endpoint);

  if (cached && ttlMs > 0 && now - cached.timestamp < ttlMs) {
    return cached.data;
  }

  let response;
  try {
    const headers = {
      Accept: 'application/json',
      'User-Agent': `OtomasyumShopify/${VERSION}`,
      'X-Forwarded-For': userIp,
    };
    // Domain allowlist için Referer zorunlu (panelde kayıtlı site URL ile aynı host)
    const referer = SITE_URL || (SHOPIFY_SHOP ? `https://${SHOPIFY_SHOP}` : '');
    if (referer) {
      headers.Referer = referer.endsWith('/') ? referer : `${referer}/`;
    }

    response = await fetch(url, {
      headers,
      signal: AbortSignal.timeout(8_000),
    });
  } catch (err) {
    console.warn('[Otomasyum] Content API network error:', err.message);
    return cached?.data ?? null;
  }

  if (response.status === 429 || response.status >= 500) {
    console.warn('[Otomasyum] Content API error:', response.status, endpoint);
    return cached?.data ?? null;
  }
  if (!response.ok) {
    return null;
  }

  let decoded;
  try {
    decoded = await response.json();
  } catch {
    return null;
  }

  if (ttlMs > 0) {
    _contentCache.set(endpoint, { data: decoded, timestamp: now });
  }

  return decoded;
}

function contentApiClearCache(endpoint = null) {
  if (endpoint === null) {
    _contentCache.clear();
  } else {
    _contentCache.delete(endpoint);
  }
}

async function otomasyumBlog(page = 1, perPage = 10, userIp) {
  return contentApiGet(`blog?page=${page}&per_page=${perPage}`, { userIp });
}

async function otomasyumBlogPost(slug, userIp) {
  return contentApiGet(`blog/${encodeURIComponent(slug)}`, { userIp });
}

async function otomasyumPages(userIp) {
  return contentApiGet('pages', { userIp });
}

async function otomasyumServices(page = 1, perPage = 20, userIp) {
  return contentApiGet(`services?page=${page}&per_page=${perPage}`, { userIp });
}

async function otomasyumSiteInfo(userIp) {
  return contentApiGet('site', { userIp });
}

/**
 * Panel → Shopify: cache temizleme endpoint örneği
 *
 * app.post('/otomasyum/cache-clear', express.json(), (req, res) => {
 *   const secret = req.get('x-otomasyum-secret') || req.get('X-Otomasyum-Secret');
 *   if (secret !== process.env.OTOMASYUM_CACHE_CLEAR_SECRET) {
 *     return res.status(403).json({ error: 'Forbidden' });
 *   }
 *   const event = req.get('X-Otomasyum-Event');
 *   if (event && event !== 'content.updated') {
 *     return res.status(403).json({ error: 'Invalid event' });
 *   }
 *   contentApiClearCache();
 *   res.json({ ok: true, cleared_files: 1, cleared_at: new Date().toISOString() });
 * });
 */

/**
 * Panel blog yazısını Shopify Blog Article olarak yayınlar (push).
 * Tercihen panel CMS Platform → Shopify + auto_publish kullanın;
 * bu yardımcı custom app tarafında manuel/senkron senaryolar içindir.
 *
 * @param {{ title: string, content?: string, body_html?: string, slug?: string, handle?: string, excerpt?: string, summary_html?: string }} post
 * @param {{ shop?: string, accessToken?: string, blogId?: string, articleId?: string|number }} [opts]
 */
async function publishArticle(post, opts = {}) {
  const shop = (opts.shop || SHOPIFY_SHOP || '').replace(/^https?:\/\//i, '').replace(/\/$/, '');
  const token = opts.accessToken || SHOPIFY_ADMIN_TOKEN;
  const blogId = String(opts.blogId || SHOPIFY_BLOG_ID || '');
  if (!shop || !token || !blogId) {
    throw new Error('SHOPIFY_SHOP, SHOPIFY_ADMIN_TOKEN ve SHOPIFY_BLOG_ID gerekli');
  }

  const article = {
    title: post.title,
    body_html: post.body_html || post.content || '',
    handle: post.handle || post.slug || undefined,
    summary_html: post.summary_html || post.excerpt || undefined,
    published: true,
  };

  const articleId = opts.articleId ? String(opts.articleId) : '';
  const base = `https://${shop}/admin/api/${SHOPIFY_API_VERSION}/blogs/${blogId}/articles`;
  const url = articleId ? `${base}/${articleId}.json` : `${base}.json`;
  const method = articleId ? 'PUT' : 'POST';
  const body = { article: articleId ? { ...article, id: Number(articleId) } : article };

  const response = await fetch(url, {
    method,
    headers: {
      'Content-Type': 'application/json',
      Accept: 'application/json',
      'X-Shopify-Access-Token': token,
      'User-Agent': `OtomasyumShopify/${VERSION}`,
    },
    body: JSON.stringify(body),
    signal: AbortSignal.timeout(15_000),
  });

  if (!response.ok) {
    const text = await response.text().catch(() => '');
    throw new Error(`Shopify article ${method} failed: ${response.status} ${text}`);
  }

  return response.json();
}

module.exports = {
  VERSION,
  API_BASE,
  SHOPIFY_TOPIC_ACTIONS,
  mapShopifyTopicToAction,
  verifyShopifyWebhookHmac,
  notifyOtomasyum,
  createShopifyWebhookHandler,
  contentApiGet,
  contentApiClearCache,
  publishArticle,
  otomasyumBlog,
  otomasyumBlogPost,
  otomasyumPages,
  otomasyumServices,
  otomasyumSiteInfo,
  ordersCreate: exports.ordersCreate,
  productsUpdate: exports.productsUpdate,
};
