<?php
declare(strict_types=1);

header('Content-Type: application/json; charset=utf-8');

$cfg = require __DIR__ . '/../config.php';
require_once __DIR__ . '/../lib/content_drafts.php';
require_once __DIR__ . '/../lib/content_wp.php';

function respond(int $code, array $payload): never {
  http_response_code($code);
  echo json_encode($payload, JSON_UNESCAPED_SLASHES);
  exit;
}

function release_draft_lock($handle): void {
  if (is_resource($handle)) {
    flock($handle, LOCK_UN);
    fclose($handle);
  }
}

function respond_with_lock(int $code, array $payload, $handle): never {
  release_draft_lock($handle);
  respond($code, $payload);
}

$raw = file_get_contents('php://input') ?: '';
$body = $raw === '' ? [] : json_decode($raw, true);
if (!is_array($body)) {
  respond(400, ['ok' => false, 'error' => 'Invalid JSON']);
}

$ref = trim((string)($body['ref'] ?? ''));
$draftId = trim((string)($body['draft'] ?? ''));
$token = trim((string)($body['token'] ?? ''));

if ($ref === '' || !preg_match('/^t_[a-f0-9]{16}$/', $ref)) {
  respond(400, ['ok' => false, 'error' => 'Invalid tenant_ref']);
}

if ($draftId === '') {
  respond(400, ['ok' => false, 'error' => 'Missing draft']);
}

if ($token === '') {
  respond(403, ['ok' => false, 'error' => 'Missing approve token']);
}

$paths = tenant_paths($cfg, $ref);
if (!is_dir($paths['tenantDir'])) {
  respond(404, ['ok' => false, 'error' => 'Tenant not found']);
}

$draftPath = content_draft_path($cfg, $ref, $draftId);
if (!is_file($draftPath)) {
  respond(404, ['ok' => false, 'error' => 'Draft not found']);
}

$lockHandle = fopen($draftPath, 'r+');
if ($lockHandle === false) {
  respond(500, ['ok' => false, 'error' => 'Unable to read draft']);
}

if (!flock($lockHandle, LOCK_EX | LOCK_NB)) {
  fclose($lockHandle);
  respond(409, ['ok' => false, 'error' => 'Approve already in progress']);
}

rewind($lockHandle);
$rawDraft = stream_get_contents($lockHandle);
if ($rawDraft === false) {
  respond_with_lock(500, ['ok' => false, 'error' => 'Failed to read draft'], $lockHandle);
}

$draft = json_decode($rawDraft, true);
if (!is_array($draft)) {
  respond_with_lock(404, ['ok' => false, 'error' => 'Draft not found'], $lockHandle);
}

$status = strtolower((string)($draft['status'] ?? ''));
if ($status === 'published') {
  $wpPostId = (int)($draft['wp_post_id'] ?? 0);
  $wpLink = (string)($draft['wp_link'] ?? '');
  respond_with_lock(200, [
    'ok' => true,
    'draft_id' => $draftId,
    'wp_post_id' => $wpPostId,
    'wp_link' => $wpLink,
    'status' => 'published',
  ], $lockHandle);
}

$approveToken = trim((string)($draft['approve_token'] ?? ''));
if ($approveToken === '' || !hash_equals($approveToken, $token)) {
  respond_with_lock(403, ['ok' => false, 'error' => 'Invalid approve token'], $lockHandle);
}

$approveTtl = (int)($cfg['approve_token_ttl_secs'] ?? 604800);
if ($approveTtl <= 0) {
  $approveTtl = 604800;
}
$expiresAt = null;
$approveExpires = trim((string)($draft['approve_expires_at'] ?? ''));
if ($approveExpires !== '') {
  $expiresAt = strtotime($approveExpires);
}
if ($expiresAt === false || $expiresAt === null) {
  $createdTs = strtotime((string)($draft['created_at'] ?? ''));
  if ($createdTs !== false) {
    $expiresAt = $createdTs + $approveTtl;
  }
}
if ($expiresAt === null) {
  respond_with_lock(403, ['ok' => false, 'error' => 'Invalid approve token'], $lockHandle);
}
if ($expiresAt < time()) {
  respond_with_lock(403, ['ok' => false, 'error' => 'Expired approve token'], $lockHandle);
}

$draft['status'] = 'approved';
$draft['approved_at'] = date('c');

try {
  $wpCreds = wp_credentials($cfg, $ref);
} catch (Throwable $e) {
  $draft['status'] = 'failed';
  $draft['last_error'] = 'wp_credentials_error';
  $draft['last_error_details'] = $e->getMessage();
  content_save_draft($cfg, $ref, $draftId, $draft);
  respond_with_lock(400, ['ok' => false, 'error' => 'Unable to load WordPress credentials', 'details' => $e->getMessage()], $lockHandle);
}

$postPayload = [
  'title' => (string)($draft['title'] ?? 'Untitled Draft'),
  'content' => (string)($draft['html'] ?? ''),
  'excerpt' => (string)($draft['plaintext_excerpt'] ?? ''),
  'status' => 'publish',
];

$publish = wp_publish_post($wpCreds, $postPayload);
if (!$publish['ok']) {
  $draft['status'] = 'failed';
  $draft['last_error'] = 'wordpress_publish_failed';
  $draft['last_error_details'] = $publish['error'] !== '' ? $publish['error'] : ('http_' . $publish['http']);
  content_save_draft($cfg, $ref, $draftId, $draft);
  respond_with_lock(502, [
    'ok' => false,
    'error' => 'WordPress publish failed',
    'details' => $publish['error'],
    'http_code' => $publish['http'],
  ], $lockHandle);
}

$response = json_decode($publish['body'], true);
if (!is_array($response)) {
  $draft['status'] = 'failed';
  $draft['last_error'] = 'wordpress_json_invalid';
  $draft['last_error_details'] = substr($publish['body'], 0, 400);
  content_save_draft($cfg, $ref, $draftId, $draft);
  respond_with_lock(502, ['ok' => false, 'error' => 'Invalid WordPress response', 'body' => substr($publish['body'], 0, 400)], $lockHandle);
}

$draftPostId = (int)($response['id'] ?? 0);
$draftLink = (string)($response['link'] ?? '');
$draft['status'] = 'published';
$draft['published_at'] = date('c');
$draft['wp_post_id'] = $draftPostId;
$draft['wp_link'] = $draftLink;
$draft['approve_token'] = null;
$draft['approve_expires_at'] = null;
$draft['approve_token_used_at'] = date('c');
$draft['last_error'] = null;
$draft['last_error_details'] = null;

if (!content_save_draft($cfg, $ref, $draftId, $draft)) {
  respond_with_lock(500, ['ok' => false, 'error' => 'Failed to persist draft state'], $lockHandle);
}

release_draft_lock($lockHandle);
respond(200, [
  'ok' => true,
  'draft_id' => $draftId,
  'wp_post_id' => $draftPostId,
  'wp_link' => $draftLink,
  'status' => $draft['status'],
]);
