<?php
declare(strict_types=1);

/**
 * IndexWell WordPress Publisher endpoint v1.4.2 PHP 7 compatible
 *
 * May be uploaded under wp-content/site-sync/; WordPress is located automatically in parent directories.
 * This version is WordPress-only and does not create iw-posts, .indexwell-publisher,
 * .private or any other filesystem storage directory.
 */

const IW_PUBLISHER_VERSION = '1.4.2-php7';
const IW_MAX_BODY_BYTES = 1048576;
const IW_MAX_CLOCK_SKEW = 300;
const IW_OPTION_CONFIG = 'indexwell_publisher_config_v2';
const IW_OPTION_SETUP = 'indexwell_publisher_setup_v2';
const IW_OPTION_STATE = 'indexwell_publisher_state_v2';

function iw_json($data, $status = 200)
{
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('X-Content-Type-Options: nosniff');
    header('X-Robots-Tag: noindex, nofollow, noarchive', true);
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function iw_plain($text, $status = 200)
{
    http_response_code($status);
    header('Content-Type: text/plain; charset=utf-8');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('X-Robots-Tag: noindex, nofollow, noarchive', true);
    header('X-Content-Type-Options: nosniff');
    header('X-IndexWell-Publisher-Version: ' . IW_PUBLISHER_VERSION);
    echo trim($text);
    exit;
}

function iw_find_wp_load()
{
    $candidates = [];
    $dir = __DIR__;
    for ($i = 0; $i < 5; $i++) {
        $candidates[] = $dir . DIRECTORY_SEPARATOR . 'wp-load.php';
        $parent = dirname($dir);
        if ($parent === $dir) break;
        $dir = $parent;
    }

    $documentRoot = rtrim((string)($_SERVER['DOCUMENT_ROOT'] ?? ''), '/\\');
    if ($documentRoot !== '') {
        $candidates[] = $documentRoot . DIRECTORY_SEPARATOR . 'wp-load.php';
        foreach ((array)glob($documentRoot . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . 'wp-load.php') as $child) {
            $candidates[] = $child;
        }
    }

    foreach (array_unique($candidates) as $candidate) {
        if (is_file($candidate) && is_readable($candidate)) return $candidate;
    }
    return null;
}

function iw_boot_wordpress()
{
    if (function_exists('wp_insert_post') && function_exists('get_option')) return;

    $wpLoad = iw_find_wp_load();
    if ($wpLoad === null) {
        iw_plain('WordPress bulunamadı', 500);
    }

    if (!defined('WP_USE_THEMES')) define('WP_USE_THEMES', false);
    ob_start();
    try {
        require_once $wpLoad;
    } finally {
        if (ob_get_level() > 0) ob_end_clean();
    }

    if (!function_exists('wp_insert_post') || !function_exists('get_option')) {
        iw_plain('WordPress yüklenemedi', 500);
    }
}

function iw_e($value)
{
    return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

function iw_cut($value, $max)
{
    return function_exists('mb_substr') ? mb_substr($value, 0, $max, 'UTF-8') : substr($value, 0, $max);
}

function iw_text($value, $max)
{
    $value = trim(preg_replace('/\s+/u', ' ', strip_tags((string)$value)) ?? '');
    return iw_cut($value, $max);
}

function iw_slug($value)
{
    if (function_exists('sanitize_title')) {
        $slug = (string)sanitize_title($value);
        return substr($slug !== '' ? $slug : 'article', 0, 80);
    }
    $value = strtolower(trim($value));
    $value = trim((string)preg_replace('/[^a-z0-9]+/', '-', $value), '-');
    return substr($value !== '' ? $value : 'article', 0, 80);
}

function iw_valid_http_url($url)
{
    if (!filter_var($url, FILTER_VALIDATE_URL)) return false;
    return in_array(strtolower((string)parse_url($url, PHP_URL_SCHEME)), ['http', 'https'], true);
}

function iw_config()
{
    $value = get_option(IW_OPTION_CONFIG, []);
    return is_array($value) ? $value : [];
}

function iw_save_config($config)
{
    update_option(IW_OPTION_CONFIG, $config, false);
}

function iw_setup_code()
{
    $existing = strtoupper(trim((string)get_option(IW_OPTION_SETUP, '')));
    if (preg_match('/^[A-Z0-9]{8}$/', $existing)) return $existing;

    $alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    $code = '';
    for ($i = 0; $i < 8; $i++) {
        $code .= $alphabet[random_int(0, strlen($alphabet) - 1)];
    }
    update_option(IW_OPTION_SETUP, $code, false);
    return $code;
}

function iw_set_state($state)
{
    $allowed = ['Sipariş alındı', 'Sipariş tamamlanıyor', 'Sipariş tamamlandı'];
    if (!in_array($state, $allowed, true)) return;
    update_option(IW_OPTION_STATE, ['state'=>$state, 'updated_at'=>gmdate('c')], false);
}

function iw_get_state()
{
    $row = get_option(IW_OPTION_STATE, []);
    $state = is_array($row) ? (string)($row['state'] ?? '') : '';
    return in_array($state, ['Sipariş alındı', 'Sipariş tamamlanıyor', 'Sipariş tamamlandı'], true)
        ? $state
        : 'Sipariş alındı';
}

function iw_log($event, $context = [])
{
    error_log('[IndexWell Publisher] ' . json_encode([
        'time'=>gmdate('c'),
        'event'=>$event,
        'context'=>$context,
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}

function iw_verify_nonce($nonce, $timestamp)
{
    if (!preg_match('/^[A-Za-z0-9_-]{16,128}$/', $nonce)) {
        iw_json(['ok'=>false, 'error'=>'Invalid nonce.'], 401);
    }

    $key = 'iw_pub_nonce_' . substr(hash('sha256', $nonce), 0, 40);
    if (get_transient($key) !== false) {
        iw_json(['ok'=>false, 'error'=>'Replay request rejected.'], 409);
    }
    set_transient($key, $timestamp, 15 * MINUTE_IN_SECONDS);
}

function iw_verify_signed_request($body, $config)
{
    $secret = (string)($config['secret'] ?? '');
    if (strlen($secret) < 32) iw_json(['ok'=>false, 'error'=>'Publisher is not paired.'], 503);

    $timestamp = (int)($_SERVER['HTTP_X_INDEXWELL_TIMESTAMP'] ?? 0);
    $nonce = trim((string)($_SERVER['HTTP_X_INDEXWELL_NONCE'] ?? ''));
    $signature = strtolower(trim((string)($_SERVER['HTTP_X_INDEXWELL_SIGNATURE'] ?? '')));

    if ($timestamp < 1 || abs(time() - $timestamp) > IW_MAX_CLOCK_SKEW) {
        iw_json(['ok'=>false, 'error'=>'Expired request timestamp.'], 401);
    }
    if (!preg_match('/^[a-f0-9]{64}$/', $signature)) {
        iw_json(['ok'=>false, 'error'=>'Invalid signature.'], 401);
    }

    $expected = hash_hmac('sha256', $timestamp . "\n" . $nonce . "\n" . $body, $secret);
    if (!hash_equals($expected, $signature)) {
        iw_log('signature_rejected');
        iw_json(['ok'=>false, 'error'=>'Signature verification failed.'], 401);
    }
    iw_verify_nonce($nonce, $timestamp);
}

function iw_wp_author_id()
{
    if (function_exists('get_users')) {
        $users = get_users([
            'role'=>'administrator',
            'number'=>1,
            'fields'=>'ID',
            'orderby'=>'ID',
            'order'=>'ASC',
        ]);
        if (is_array($users) && isset($users[0])) return max(1, (int)$users[0]);
    }
    return 1;
}

function iw_anchor_html($anchor, $target, $linkRel)
{
    $rel = $linkRel === 'nofollow'
        ? ' rel="nofollow noopener noreferrer"'
        : ' rel="noopener noreferrer"';
    return '<a href="' . iw_e($target) . '"' . $rel . '>' . iw_e($anchor) . '</a>';
}

function iw_paragraphs($text)
{
    $parts = preg_split('/\n\s*\n|\r\n\s*\r\n/', trim($text)) ?: [];
    $out = [];
    foreach ($parts as $part) {
        $part = trim($part);
        if ($part !== '') $out[] = '<p>' . nl2br(iw_e($part), false) . '</p>';
    }
    return $out;
}

function iw_article_content($payload, $orderId)
{
    $title = iw_text($payload['title'] ?? '', 180);
    $intro = trim((string)($payload['intro'] ?? ''));
    $anchor = iw_text($payload['anchor_text'] ?? '', 180);
    $target = trim((string)($payload['target_url'] ?? ''));
    $linkRel = strtolower(trim((string)($payload['link_rel'] ?? 'dofollow')));

    if ($title === '' || $anchor === '' || !iw_valid_http_url($target)) {
        throw new RuntimeException('Article title, anchor or target URL is invalid.');
    }
    if (!in_array($linkRel, ['dofollow', 'nofollow'], true)) $linkRel = 'dofollow';

    $anchorLink = iw_anchor_html($anchor, $target, $linkRel);
    $sentences = [
        'Konu hakkında güncel ayrıntılar için %s kaynağı incelenebilir.',
        'İlgili bilgi ve güncel erişim ayrıntıları %s bağlantısında yer alır.',
        'Daha ayrıntılı değerlendirme için %s sayfası referans olarak kullanılabilir.',
        'Güncel bilgiye ulaşmak isteyen kullanıcılar %s kaynağını kontrol edebilir.',
        'Konuya ilişkin ek bilgiler %s bağlantısı üzerinden doğrulanabilir.',
        'Güncel açıklamalar ve erişim bilgileri için %s sayfasına bakılabilir.',
    ];
    $sentence = sprintf($sentences[hexdec(substr(hash('sha256', $orderId), 0, 2)) % count($sentences)], $anchorLink);

    $parts = iw_paragraphs($intro);
    if ($parts === []) {
        $parts[] = '<p>' . $sentence . '</p>';
    } else {
        $insertAt = count($parts) > 1 ? 1 : count($parts);
        array_splice($parts, $insertAt, 0, ['<p>' . $sentence . '</p>']);
    }

    $sections = '';
    foreach ((array)($payload['sections'] ?? []) as $section) {
        if (!is_array($section)) continue;
        $heading = iw_text($section['heading'] ?? '', 180);
        $body = trim((string)($section['body'] ?? ''));
        if ($heading !== '') $sections .= '<h2>' . iw_e($heading) . '</h2>';
        foreach (iw_paragraphs($body) as $paragraph) $sections .= $paragraph;
    }

    $content = implode("\n", $parts) . "\n" . $sections;
    return function_exists('wp_kses_post') ? (string)wp_kses_post($content) : $content;
}

function iw_wp_find_existing_post($orderId)
{
    $posts = get_posts([
        'post_type'=>'post',
        'post_status'=>'any',
        'posts_per_page'=>1,
        'fields'=>'ids',
        'meta_key'=>'_indexwell_order_id',
        'meta_value'=>$orderId,
        'no_found_rows'=>true,
        'suppress_filters'=>true,
    ]);
    return is_array($posts) && isset($posts[0]) ? (int)$posts[0] : 0;
}

function iw_publish_wordpress($payload, $orderId)
{
    $existingId = iw_wp_find_existing_post($orderId);
    if ($existingId > 0) {
        $url = (string)get_permalink($existingId);
        if ($url !== '') return ['post_id'=>$existingId, 'published_url'=>$url, 'duplicate'=>true];
    }

    $title = iw_text($payload['title'] ?? '', 180);
    $description = iw_text($payload['meta_description'] ?? '', 300);
    $slug = iw_slug((string)($payload['slug'] ?? $title)) . '-' . substr(hash('sha256', $orderId), 0, 8);
    $anchor = iw_text($payload['anchor_text'] ?? '', 180);
    $target = trim((string)($payload['target_url'] ?? ''));
    $content = iw_article_content($payload, $orderId);

    if ($title === '' || $content === '') throw new RuntimeException('WordPress post content is empty.');

    $postData = [
        'post_title'=>$title,
        'post_name'=>$slug,
        'post_content'=>$content,
        'post_excerpt'=>$description,
        'post_status'=>'publish',
        'post_type'=>'post',
        'post_author'=>iw_wp_author_id(),
        'comment_status'=>'closed',
        'ping_status'=>'closed',
        'meta_input'=>[
            '_indexwell_order_id'=>$orderId,
            '_indexwell_target_url'=>$target,
            '_indexwell_anchor_text'=>$anchor,
            '_yoast_wpseo_metadesc'=>$description,
            'rank_math_description'=>$description,
        ],
    ];

    $postId = wp_insert_post($postData, true);
    if (is_wp_error($postId)) {
        throw new RuntimeException('WordPress post could not be created: ' . $postId->get_error_message());
    }
    $postId = (int)$postId;
    if ($postId < 1) throw new RuntimeException('WordPress post could not be created.');

    clean_post_cache($postId);
    $url = (string)get_permalink($postId);
    if ($url === '') $url = (string)home_url('/?p=' . $postId);
    if (!iw_valid_http_url($url)) throw new RuntimeException('WordPress permalink could not be generated.');

    return ['post_id'=>$postId, 'published_url'=>$url, 'duplicate'=>false];
}

function iw_status_page($config)
{
    $paired = strlen((string)($config['secret'] ?? '')) >= 32;
    iw_plain($paired ? iw_get_state() : iw_setup_code());
}

try {
    iw_boot_wordpress();

    $method = strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET'));
    $config = iw_config();

    if ($method === 'GET') iw_status_page($config);
    if ($method !== 'POST') iw_json(['ok'=>false, 'error'=>'Method not allowed.'], 405);

    $length = (int)($_SERVER['CONTENT_LENGTH'] ?? 0);
    if ($length > IW_MAX_BODY_BYTES) iw_json(['ok'=>false, 'error'=>'Request is too large.'], 413);

    $body = (string)file_get_contents('php://input');
    $payload = json_decode($body, true);
    if (!is_array($payload)) iw_json(['ok'=>false, 'error'=>'Invalid JSON body.'], 400);
    $action = strtolower(trim((string)($payload['action'] ?? '')));

    if ($action === 'pair') {
        if (strlen((string)($config['secret'] ?? '')) >= 32) {
            iw_json(['ok'=>false, 'error'=>'Publisher is already paired.'], 409);
        }

        $provided = strtoupper(trim((string)($payload['setup_code'] ?? '')));
        if (!hash_equals(iw_setup_code(), $provided)) iw_json(['ok'=>false, 'error'=>'Setup code is incorrect.'], 401);

        $secret = trim((string)($payload['secret'] ?? ''));
        if (strlen($secret) < 48) iw_json(['ok'=>false, 'error'=>'Pairing secret is too short.'], 422);

        $siteName = iw_text($payload['site_name'] ?? parse_url(home_url('/'), PHP_URL_HOST), 120);
        $config = [
            'secret'=>$secret,
            'site_name'=>$siteName,
            'paired_at'=>gmdate('c'),
            'version'=>IW_PUBLISHER_VERSION,
            'mode'=>'wordpress',
        ];
        iw_save_config($config);
        delete_option(IW_OPTION_SETUP);
        iw_set_state('Sipariş alındı');
        iw_log('paired', ['site_name'=>$siteName]);

        iw_json([
            'ok'=>true,
            'paired'=>true,
            'version'=>IW_PUBLISHER_VERSION,
            'mode'=>'wordpress',
        ]);
    }

    iw_verify_signed_request($body, $config);

    if ($action === 'health') {
        iw_json([
            'ok'=>true,
            'status'=>'ready',
            'version'=>IW_PUBLISHER_VERSION,
            'mode'=>'wordpress',
            'site_name'=>(string)($config['site_name'] ?? ''),
            'wordpress_version'=>(string)($GLOBALS['wp_version'] ?? ''),
        ]);
    }

    if ($action === 'rekey') {
        $newSecret = trim((string)($payload['new_secret'] ?? ''));
        if (strlen($newSecret) < 48) iw_json(['ok'=>false, 'error'=>'New secret is too short.'], 422);
        $config['secret'] = $newSecret;
        $config['rekeyed_at'] = gmdate('c');
        iw_save_config($config);
        iw_log('rekeyed');
        iw_json(['ok'=>true, 'rekeyed'=>true]);
    }

    if ($action === 'publish') {
        $orderId = iw_text($payload['order_id'] ?? '', 100);
        if (!preg_match('/^[A-Za-z0-9._:-]{8,100}$/', $orderId)) {
            iw_json(['ok'=>false, 'error'=>'Invalid order ID.'], 422);
        }

        iw_set_state('Sipariş tamamlanıyor');
        $result = iw_publish_wordpress($payload, $orderId);
        iw_set_state('Sipariş tamamlandı');
        iw_log('published', ['order_id'=>$orderId, 'post_id'=>$result['post_id']]);

        iw_json([
            'ok'=>true,
            'published_url'=>$result['published_url'],
            'mode'=>'wordpress',
            'post_id'=>$result['post_id'],
            'duplicate'=>$result['duplicate'],
            'version'=>IW_PUBLISHER_VERSION,
        ]);
    }

    if ($action === 'delete') {
        $orderId = iw_text($payload['order_id'] ?? '', 100);
        $postId = iw_wp_find_existing_post($orderId);
        if ($postId > 0) wp_delete_post($postId, true);
        iw_log('deleted', ['order_id'=>$orderId, 'post_id'=>$postId]);
        iw_json(['ok'=>true, 'deleted'=>$postId > 0]);
    }

    iw_json(['ok'=>false, 'error'=>'Unknown action.'], 400);
} catch (Throwable $e) {
    iw_log('error', ['message'=>$e->getMessage()]);
    iw_json(['ok'=>false, 'error'=>$e->getMessage()], 500);
}
