<?php

declare(strict_types=1);

require_once __DIR__ . '/../lib/Env.php';
require_once __DIR__ . '/../lib/Db.php';
require_once __DIR__ . '/../lib/Logger.php';
require_once __DIR__ . '/../lib/WpPublisher.php';
require_once __DIR__ . '/../lib/Mailer.php';
require_once __DIR__ . '/../lib/HtmlSanitizer.php';

Env::load(__DIR__ . '/../.env');

header('Content-Type: text/html; charset=utf-8');

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$token = '';
if ($method === 'POST') {
    $token = $_POST['token'] ?? '';
} else {
    $token = $_GET['token'] ?? '';
}

$token = trim($token);
if ($token === '') {
    http_response_code(400);
    echo '<p>Token is required.</p>';
    exit;
}

$pdo = Db::getConnection();
$approvalStmt = $pdo->prepare('SELECT * FROM approvals WHERE token = :token LIMIT 1');
$approvalStmt->execute([':token' => $token]);
$approval = $approvalStmt->fetch(PDO::FETCH_ASSOC);

if (!$approval) {
    http_response_code(404);
    echo '<p>Invalid approval token.</p>';
    exit;
}

$expiresAt = null;
if (!empty($approval['created_at'])) {
    try {
        $expiresAt = (new DateTimeImmutable($approval['created_at']))->modify('+7 days');
    } catch (Throwable $dateEx) {
        Logger::log('error', 'Unable to parse approval timestamp: ' . $dateEx->getMessage());
    }
}

if ($expiresAt !== null && new DateTimeImmutable() > $expiresAt) {
    echo '<p>This approval token expired on ' . htmlspecialchars($expiresAt->format('Y-m-d H:i:s'), ENT_QUOTES, 'UTF-8') . '.</p>';
    exit;
}

$draftStmt = $pdo->prepare('SELECT * FROM drafts WHERE id = :id LIMIT 1');
$draftStmt->execute([':id' => $approval['draft_id']]);
$draft = $draftStmt->fetch(PDO::FETCH_ASSOC);

if (!$draft) {
    http_response_code(404);
    echo '<p>Draft not found.</p>';
    exit;
}

if ($method === 'GET') {
    if ($draft['status'] === 'published') {
        echo '<p>This draft has already been published.</p>';
        exit;
    }

    $baseUrl = rtrim(Env::get('APP_BASE_URL', ''), '/');
    $previewUrl = ($baseUrl !== '' ? $baseUrl : '#') . '/preview.php?id=' . $draft['id'];
    ?>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Approve draft: <?= htmlspecialchars($draft['title'] ?? 'Draft', ENT_QUOTES, 'UTF-8') ?></title>
    </head>
    <body>
        <p>Topic: <?= htmlspecialchars($draft['topic'] ?? '', ENT_QUOTES, 'UTF-8') ?></p>
        <p>Title: <?= htmlspecialchars($draft['title'] ?? '', ENT_QUOTES, 'UTF-8') ?></p>
        <p>Current status: <?= htmlspecialchars($draft['status'] ?? 'unknown', ENT_QUOTES, 'UTF-8') ?></p>
        <p><a href="<?= htmlspecialchars($previewUrl, ENT_QUOTES, 'UTF-8') ?>">Preview draft</a></p>
        <form method="post">
            <input type="hidden" name="token" value="<?= htmlspecialchars($token, ENT_QUOTES, 'UTF-8') ?>">
            <button type="submit">Publish to WordPress</button>
        </form>
    </body>
    </html>
    <?php
    exit;
}

if ($draft['status'] === 'published') {
    echo '<p>This draft has already been published.</p>';
    exit;
}

$wpUrl = null;

try {
    $publisher = new WpPublisher();
    $mediaId = null;
    $imagePath = $draft['image_path'] ?? '';
    if ($imagePath !== '' && file_exists($imagePath)) {
        $media = $publisher->uploadImage(
            $imagePath,
            ($draft['slug'] ?: 'featured-image') . '.png',
            $draft['title'] ?? ''
        );
        $mediaId = (int)($media['id'] ?? 0) ?: null;
    } else {
        Logger::log('warning', "No featured image found for draft {$draft['id']}; skipping upload.");
    }

    $defaultStatus = trim(Env::get('WP_DEFAULT_STATUS', 'publish'));
    if ($defaultStatus === '') {
        $defaultStatus = 'publish';
    }

    $sanitizedContent = sanitizeHtml($draft['content_html'] ?? '');
    Logger::log('info', "Publishing sanitized HTML for draft {$draft['id']}");

    $postData = [
        'title' => $draft['title'],
        'content' => $sanitizedContent,
        'slug' => $draft['slug'],
        'status' => $defaultStatus,
        'excerpt' => $draft['meta_description'] ?? '',
    ];

    $categoryIds = parseIdList(Env::get('WP_DEFAULT_CATEGORY_ID'));
    if ($categoryIds !== []) {
        $postData['categories'] = $categoryIds;
    }

    $tagIds = parseIdList(Env::get('WP_DEFAULT_TAGS'));
    if ($tagIds !== []) {
        $postData['tags'] = $tagIds;
    }

    if ($mediaId !== null) {
        $postData['featured_media'] = $mediaId;
    }

    $post = $publisher->createPost($postData);
    $wpUrl = $post['link'] ?? ($post['guid']['rendered'] ?? null);

    $pdo->beginTransaction();

    $updateDraft = $pdo->prepare('UPDATE drafts SET status = :status, updated_at = CURRENT_TIMESTAMP WHERE id = :id');
    $updateDraft->execute([
        ':status' => 'published',
        ':id' => $draft['id'],
    ]);

    $publishStmt = $pdo->prepare(
        'INSERT INTO wp_publish (draft_id, wp_post_id, wp_url, published_at, status) VALUES (:draft_id, :wp_post_id, :wp_url, CURRENT_TIMESTAMP, :status)'
    );
    $publishStmt->execute([
        ':draft_id' => $draft['id'],
        ':wp_post_id' => $post['id'] ?? null,
        ':wp_url' => $wpUrl,
        ':status' => 'published',
    ]);

    $approvalUpdate = $pdo->prepare('UPDATE approvals SET action = :action, note = :note WHERE id = :id');
    $approvalUpdate->execute([
        ':action' => 'approved',
        ':note' => 'Published to WordPress: ' . ($wpUrl ?? 'unknown'),
        ':id' => $approval['id'],
    ]);

    $pdo->commit();

    $mailer = new Mailer();
    $mailer->send(
        'Blog published: ' . ($draft['title'] ?? 'Untitled'),
        'The blog has been published to WordPress at: ' . ($wpUrl ?? 'URL not available')
    );

    Logger::log('info', "Draft {$draft['id']} published to WordPress at {$wpUrl}");

    echo '<p>Post published successfully! View it here: <a href="' . htmlspecialchars($wpUrl ?? '#', ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($wpUrl ?? 'View post', ENT_QUOTES, 'UTF-8') . '</a></p>';
    exit;
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    $loggerMessage = sprintf('Approval failed for draft %s: %s', $draft['id'], $e->getMessage());
    Logger::log('error', $loggerMessage);

    $failStmt = $pdo->prepare('UPDATE drafts SET status = :status, updated_at = CURRENT_TIMESTAMP WHERE id = :id');
    $failStmt->execute([
        ':status' => 'publish_failed',
        ':id' => $draft['id'],
    ]);

    $publishFail = $pdo->prepare(
        'INSERT INTO wp_publish (draft_id, status, error) VALUES (:draft_id, :status, :error)'
    );
    $publishFail->execute([
        ':draft_id' => $draft['id'],
        ':status' => 'publish_failed',
        ':error' => $e->getMessage(),
    ]);

    echo '<p>Publishing failed: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8') . '</p>';
    exit;
}

function parseIdList(?string $value): array
{
    if ($value === null) {
        return [];
    }

    $parts = array_filter(array_map('trim', explode(',', $value)), fn(string $item): bool => $item !== '');
    $ids = [];
    foreach ($parts as $part) {
        if (ctype_digit($part)) {
            $id = (int)$part;
            if ($id > 0) {
                $ids[] = $id;
            }
        }
    }

    return $ids;
}
