<?php
define('CIYUN_PUBLISHER_VERSION', '1.0.0');

$discuzRoot = dirname(__DIR__, 3) . '/';
if (file_exists($discuzRoot . 'source/class/class_core.php')) {
    require_once $discuzRoot . 'source/class/class_core.php';
    $discuz = C::app();
    $discuz->init();
}

try {
    if (($_SERVER['REQUEST_METHOD'] ?? '') === 'GET' && ($_GET['action'] ?? '') === 'image') {
        ciyun_serve_image($_GET['file'] ?? '');
    }
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
        ciyun_response(405, ['success' => false, 'message' => '仅支持 POST 请求']);
    }
    if (stripos($_SERVER['CONTENT_TYPE'] ?? '', 'application/json') === false) {
        ciyun_response(400, ['success' => false, 'message' => '请求内容必须是 application/json']);
    }
    $config = ciyun_config();
    ciyun_check_token($config);
    ciyun_check_ip($config);
    $data = json_decode(file_get_contents('php://input'), true);
    if (!is_array($data)) {
        ciyun_response(400, ['success' => false, 'message' => 'JSON 格式不正确']);
    }
    if (($data['action'] ?? '') === 'self_check') {
        ciyun_response(200, ciyun_self_check($config));
    }
    if (($data['action'] ?? '') === 'version') {
        ciyun_response(200, ciyun_version_payload());
    }
    if (($data['action'] ?? '') === 'logs') {
        ciyun_response(200, ['success' => true, 'items' => ciyun_recent_logs(intval($data['limit'] ?? 50))]);
    }
    if (($data['action'] ?? '') === 'terms') {
        ciyun_response(200, ['success' => true, 'items' => ciyun_terms($data['type'] ?? 'category')]);
    }
    if (($data['action'] ?? '') === 'upload_image') {
        ciyun_response(200, ciyun_upload_image($data));
    }
    ciyun_validate($data);
    $threadId = ciyun_save_thread($data, $config);
    ciyun_log('success', $data['title'], 'tid=' . $threadId);
    ciyun_response(200, ['success' => true, 'post_id' => $threadId, 'message' => '发帖成功']);
} catch (Throwable $e) {
    ciyun_log('error', '', $e->getMessage());
    ciyun_response(500, ['success' => false, 'message' => '服务器错误', 'error' => $e->getMessage()]);
}

function ciyun_config()
{
    global $_G;
    $plugin = $_G['cache']['plugin']['ciyun_publisher'] ?? [];
    $file = __DIR__ . '/config.php';
    $fallback = file_exists($file) ? include $file : [];
    return [
        'token' => (string)($plugin['token'] ?? $fallback['token'] ?? ''),
        'whitelist_ips' => (string)($plugin['whitelist_ips'] ?? $fallback['whitelist_ips'] ?? ''),
        'force_draft' => (string)($plugin['force_draft'] ?? $fallback['force_draft'] ?? '1'),
        'default_author_id' => (string)($plugin['default_author_id'] ?? $fallback['default_author_id'] ?? '1'),
    ];
}

function ciyun_self_check($config)
{
    return [
        'success' => true,
        'message' => '自检通过',
        'checks' => [
            'token' => strlen($config['token'] ?? '') >= 32,
            'log_writable' => ciyun_log_writable(),
            'forums' => count(ciyun_terms('category')),
            'authors' => count(ciyun_terms('author')),
            'force_draft' => ($config['force_draft'] ?? '1') === '1',
        ],
        'api' => '/source/plugin/ciyun_publisher/api.php',
        'version' => CIYUN_PUBLISHER_VERSION,
    ];
}

function ciyun_version_payload()
{
    return [
        'success' => true,
        'name' => 'CiyunPublisher',
        'cms' => 'discuz',
        'version' => CIYUN_PUBLISHER_VERSION,
    ];
}

function ciyun_terms($type)
{
    if ($type === 'author') {
        return ciyun_authors();
    }
    return ciyun_forums();
}

function ciyun_forums()
{
    $items = [];
    if (!class_exists('DB')) {
        return $items;
    }
    $query = DB::query("SELECT fid, name FROM " . DB::table('forum_forum') . " WHERE type='forum' ORDER BY fid ASC");
    while ($row = DB::fetch($query)) {
        $items[] = ['id' => intval($row['fid']), 'name' => (string)$row['name']];
    }
    return $items;
}

function ciyun_authors()
{
    $items = [];
    if (!class_exists('DB')) {
        return $items;
    }
    $query = DB::query("SELECT uid, username FROM " . DB::table('common_member') . " ORDER BY uid ASC LIMIT 200");
    while ($row = DB::fetch($query)) {
        $items[] = ['id' => intval($row['uid']), 'name' => (string)$row['username']];
    }
    return $items;
}

function ciyun_upload_image($data)
{
    $raw = base64_decode((string)($data['data_base64'] ?? ''), true);
    if ($raw === false || $raw === '') {
        ciyun_response(400, ['success' => false, 'message' => '图片内容无效']);
    }
    if (strlen($raw) > 5 * 1024 * 1024) {
        ciyun_response(400, ['success' => false, 'message' => '图片超过 5MB']);
    }
    if (ciyun_reject_non_image_content_type($data['content_type'] ?? '')) {
        ciyun_response(400, ['success' => false, 'message' => '图片类型无效']);
    }
    $contentType = ciyun_image_content_type($data['content_type'] ?? '', $data['filename'] ?? '');
    $extension = ciyun_image_extension($contentType, $data['filename'] ?? '');
    $dir = __DIR__ . '/uploads';
    if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
        ciyun_response(500, ['success' => false, 'message' => '图片目录不可写']);
    }
    $filename = date('YmdHis') . '_' . substr(md5($raw . ($data['filename'] ?? '')), 0, 12) . $extension;
    $path = $dir . '/' . $filename;
    if (file_put_contents($path, $raw) === false) {
        ciyun_response(500, ['success' => false, 'message' => '图片保存失败']);
    }
    return ['success' => true, 'url' => ciyun_image_url($filename)];
}

function ciyun_serve_image($file)
{
    $filename = basename((string)$file);
    if (!preg_match('/^[A-Za-z0-9._-]+$/', $filename)) {
        ciyun_response(404, ['success' => false, 'message' => '图片不存在']);
    }
    $path = __DIR__ . '/uploads/' . $filename;
    if (!is_file($path)) {
        ciyun_response(404, ['success' => false, 'message' => '图片不存在']);
    }
    header('Content-Type: ' . ciyun_image_content_type('', $filename));
    header('Cache-Control: public, max-age=31536000');
    readfile($path);
    exit;
}

function ciyun_image_url($filename)
{
    $scheme = ciyun_request_scheme();
    $host = $_SERVER['HTTP_HOST'] ?? '';
    $script = $_SERVER['SCRIPT_NAME'] ?? '';
    return $scheme . '://' . $host . $script . '?action=image&file=' . rawurlencode($filename);
}

function ciyun_request_scheme()
{
    $forwarded = strtolower(trim(explode(',', (string)($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''))[0]));
    if (in_array($forwarded, ['http', 'https'], true)) {
        return $forwarded;
    }
    return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
}

function ciyun_image_content_type($contentType, $filename = '')
{
    $contentType = strtolower(trim(explode(';', (string)$contentType)[0]));
    $allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
    if (in_array($contentType, $allowed, true)) {
        return $contentType;
    }
    $extension = strtolower(pathinfo((string)$filename, PATHINFO_EXTENSION));
    if ($extension === 'png') {
        return 'image/png';
    }
    if ($extension === 'gif') {
        return 'image/gif';
    }
    if ($extension === 'webp') {
        return 'image/webp';
    }
    return 'image/jpeg';
}

function ciyun_image_extension($contentType, $filename = '')
{
    $contentType = ciyun_image_content_type($contentType, $filename);
    if ($contentType === 'image/png') {
        return '.png';
    }
    if ($contentType === 'image/gif') {
        return '.gif';
    }
    if ($contentType === 'image/webp') {
        return '.webp';
    }
    return '.jpg';
}

function ciyun_reject_non_image_content_type($contentType)
{
    $contentType = strtolower(trim(explode(';', (string)$contentType)[0]));
    if ($contentType === '') {
        return false;
    }
    if (strpos($contentType, 'text/') === 0) {
        return true;
    }
    return in_array($contentType, ['application/json', 'application/xml', 'application/xhtml+xml', 'image/svg+xml'], true);
}

function ciyun_save_thread($data, $config)
{
    if (!class_exists('DB')) {
        throw new Exception('Discuz 数据库服务不可用');
    }
    $fid = intval($data['fid'] ?? $data['category_id'] ?? 0);
    if ($fid <= 0) {
        ciyun_response(400, ['success' => false, 'message' => 'fid 版块 ID 必填']);
    }
    $authorId = intval($data['author_id'] ?? $config['default_author_id'] ?? 1);
    $author = ciyun_author_name($authorId);
    $visible = ($config['force_draft'] ?? '1') === '1' || ($data['status'] ?? 'draft') !== 'publish' ? -2 : 0;
    $now = time();
    $thread = [
        'fid' => $fid,
        'author' => $author,
        'authorid' => $authorId,
        'subject' => $data['title'],
        'dateline' => $now,
        'lastpost' => $now,
        'lastposter' => $author,
        'displayorder' => $visible,
        'digest' => 0,
        'special' => 0,
        'attachment' => 0,
        'moderated' => $visible < 0 ? 1 : 0,
        'status' => 32,
        'isgroup' => 0,
        'replycredit' => 0,
    ];
    $tid = DB::insert('forum_thread', $thread, true);
    $post = [
        'fid' => $fid,
        'tid' => $tid,
        'first' => 1,
        'author' => $author,
        'authorid' => $authorId,
        'subject' => $data['title'],
        'dateline' => $now,
        'message' => ciyun_html_to_discuz($data['content']),
        'useip' => $_SERVER['REMOTE_ADDR'] ?? '',
        'invisible' => $visible,
        'anonymous' => 0,
        'usesig' => 0,
        'htmlon' => 1,
        'bbcodeoff' => 0,
        'smileyoff' => 0,
        'parseurloff' => 0,
        'attachment' => 0,
        'status' => 0,
    ];
    DB::insert('forum_post', $post);
    return $tid;
}

function ciyun_author_name($uid)
{
    if (!class_exists('DB')) {
        return 'admin';
    }
    $row = DB::fetch_first("SELECT username FROM " . DB::table('common_member') . " WHERE uid=" . intval($uid));
    return $row && !empty($row['username']) ? $row['username'] : 'admin';
}

function ciyun_html_to_discuz($html)
{
    return trim((string)$html);
}

function ciyun_recent_logs($limit)
{
    $limit = max(1, min($limit, 200));
    $file = __DIR__ . '/publish.log';
    if (!file_exists($file)) {
        return [];
    }
    $lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    if (!is_array($lines)) {
        return [];
    }
    $items = [];
    foreach (array_reverse(array_slice($lines, -$limit)) as $line) {
        $parts = explode("\t", $line, 5);
        $items[] = [
            'time' => $parts[0] ?? '',
            'ip' => $parts[1] ?? '',
            'status' => $parts[2] ?? '',
            'title' => $parts[3] ?? '',
            'message' => $parts[4] ?? '',
        ];
    }
    return $items;
}

function ciyun_check_token($config)
{
    $token = (string)($config['token'] ?? '');
    $header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
    if (strlen($token) < 32 || !preg_match('/Bearer\s+(.+)/i', $header, $m) || !hash_equals($token, trim($m[1]))) {
        ciyun_log('unauthorized', '', 'Token 错误');
        ciyun_response(401, ['success' => false, 'message' => 'Token 错误']);
    }
}

function ciyun_check_ip($config)
{
    $list = preg_split('/[\s,]+/', trim((string)($config['whitelist_ips'] ?? '')));
    $list = array_filter($list);
    if ($list && !in_array($_SERVER['REMOTE_ADDR'] ?? '', $list, true)) {
        ciyun_response(401, ['success' => false, 'message' => 'IP 不在白名单']);
    }
}

function ciyun_validate($data)
{
    if (empty($data['title']) || empty($data['content'])) {
        ciyun_response(400, ['success' => false, 'message' => 'title 和 content 必填']);
    }
    if (ciyun_strlen($data['title']) > 120 || ciyun_strlen($data['content']) > 200000) {
        ciyun_response(400, ['success' => false, 'message' => '标题或正文过长']);
    }
}

function ciyun_strlen($value)
{
    return function_exists('mb_strlen') ? mb_strlen($value, 'UTF-8') : strlen($value);
}

function ciyun_log_writable()
{
    $file = __DIR__ . '/publish.log';
    if (file_exists($file)) {
        return is_writable($file);
    }
    return is_writable(__DIR__);
}

function ciyun_log($status, $title, $message)
{
    $line = date('Y-m-d H:i:s') . "\t" . ($_SERVER['REMOTE_ADDR'] ?? '') . "\t" . $status . "\t" . str_replace(["\r", "\n"], ' ', $title) . "\t" . str_replace(["\r", "\n"], ' ', $message) . PHP_EOL;
    file_put_contents(__DIR__ . '/publish.log', $line, FILE_APPEND);
}

function ciyun_response($code, $payload)
{
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($payload, JSON_UNESCAPED_UNICODE);
    exit;
}
