<?php
namespace Phpcmf\App\Ciyun_publisher\Controllers;

class Api extends \Phpcmf\Common
{
    const CIYUN_PUBLISHER_VERSION = '1.0.0';

    public function index()
    {
        try {
            if (strtoupper($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
                $this->ciyun_response(405, ['success' => false, 'message' => 'Only POST is allowed']);
            }
            if (stripos($_SERVER['CONTENT_TYPE'] ?? '', 'application/json') === false) {
                $this->ciyun_response(400, ['success' => false, 'message' => 'Content-Type must be application/json']);
            }
            $config = $this->ciyun_config();
            $this->ciyun_check_token($config);
            $this->ciyun_check_ip($config);
            $data = json_decode(file_get_contents('php://input'), true);
            if (!is_array($data)) {
                $this->ciyun_response(400, ['success' => false, 'message' => 'Invalid JSON']);
            }
            if (($data['action'] ?? '') === 'self_check') {
                $this->ciyun_response(200, $this->ciyun_self_check($config));
            }
            if (($data['action'] ?? '') === 'version') {
                $this->ciyun_response(200, $this->ciyun_version_payload());
            }
            if (($data['action'] ?? '') === 'logs') {
                $this->ciyun_response(200, ['success' => true, 'items' => $this->ciyun_recent_logs(intval($data['limit'] ?? 50))]);
            }
            if (($data['action'] ?? '') === 'terms') {
                $this->ciyun_response(200, ['success' => true, 'items' => $this->ciyun_terms($data['type'] ?? 'category', $config)]);
            }
            $this->ciyun_validate($data);
            $postId = $this->ciyun_save_article($data, $config);
            $this->ciyun_log('success', $data['title'], 'post_id=' . $postId);
            $this->ciyun_response(200, ['success' => true, 'post_id' => $postId, 'message' => 'publish success']);
        } catch (\Throwable $e) {
            $this->ciyun_log('error', '', $e->getMessage());
            $this->ciyun_response(500, ['success' => false, 'message' => 'server error', 'error' => $e->getMessage()]);
        }
    }

    private function ciyun_config()
    {
        $default = [
            'token' => '',
            'whitelist_ips' => '',
            'force_draft' => '1',
            'module' => 'news',
            'category_field' => 'catid',
            'author_field' => 'uid',
        ];
        if (function_exists('dr_site_value')) {
            $saved = dr_site_value('ciyun_publisher');
            if (is_array($saved)) {
                return array_merge($default, $saved);
            }
        }
        return $default;
    }

    private function ciyun_self_check($config)
    {
        return [
            'success' => true,
            'message' => 'self_check ok',
            'checks' => [
                'token' => strlen($config['token'] ?? '') >= 32,
                'log_writable' => $this->ciyun_log_writable(),
                'categories' => count($this->ciyun_terms('category', $config)),
                'authors' => count($this->ciyun_terms('author', $config)),
                'force_draft' => ($config['force_draft'] ?? '1') === '1',
            ],
            'api' => '/index.php?s=ciyun_publisher&c=api&m=index',
            'module' => $config['module'] ?? 'news',
            'version' => self::CIYUN_PUBLISHER_VERSION,
        ];
    }

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

    private function ciyun_terms($type, $config)
    {
        if ($type === 'author') {
            return $this->ciyun_authors();
        }
        return $this->ciyun_categories($config);
    }

    private function ciyun_categories($config)
    {
        $items = [];
        if (!class_exists('\\Phpcmf\\Service')) {
            return $items;
        }
        try {
            $module = preg_replace('/[^a-zA-Z0-9_]/', '', (string)($config['module'] ?? 'news'));
            $field = preg_replace('/[^a-zA-Z0-9_]/', '', (string)($config['category_field'] ?? 'catid'));
            $rows = \Phpcmf\Service::M()->table($module . '_category')->select();
            foreach ((array)$rows as $row) {
                $id = intval($row[$field] ?? $row['id'] ?? $row['catid'] ?? 0);
                $name = trim((string)($row['name'] ?? $row['catname'] ?? $row['title'] ?? ''));
                if ($id > 0 && $name !== '') {
                    $items[] = ['id' => $id, 'name' => $name];
                }
            }
        } catch (\Throwable $e) {
            return [];
        }
        return $items;
    }

    private function ciyun_authors()
    {
        $items = [];
        if (!class_exists('\\Phpcmf\\Service')) {
            return $items;
        }
        try {
            $rows = \Phpcmf\Service::M()->table('admin')->select();
            foreach ((array)$rows as $row) {
                $id = intval($row['uid'] ?? $row['id'] ?? 0);
                $name = trim((string)($row['username'] ?? $row['name'] ?? $row['nickname'] ?? ''));
                if ($id > 0 && $name !== '') {
                    $items[] = ['id' => $id, 'name' => $name];
                }
            }
        } catch (\Throwable $e) {
            return [];
        }
        return $items;
    }

    private function ciyun_save_article($data, $config)
    {
        if (!class_exists('\\Phpcmf\\Service')) {
            throw new \RuntimeException('Phpcmf Service is unavailable');
        }
        $module = preg_replace('/[^a-zA-Z0-9_]/', '', (string)($config['module'] ?? 'news'));
        $categoryField = preg_replace('/[^a-zA-Z0-9_]/', '', (string)($config['category_field'] ?? 'catid'));
        $authorField = preg_replace('/[^a-zA-Z0-9_]/', '', (string)($config['author_field'] ?? 'uid'));
        $isDraft = ($config['force_draft'] ?? '1') === '1' || ($data['status'] ?? 'draft') !== 'publish';
        $now = time();
        $post = [
            'title' => $data['title'],
            'keywords' => is_array($data['tags'] ?? null) ? implode(',', $data['tags']) : '',
            'description' => $data['excerpt'] ?? '',
            'content' => $data['content'],
            'status' => $isDraft ? 0 : 9,
            'inputtime' => !empty($data['created_at']) ? strtotime($data['created_at']) : $now,
            'updatetime' => $now,
        ];
        $categoryId = intval($data['category_id'] ?? 0);
        $authorId = intval($data['author_id'] ?? 0);
        if ($categoryId > 0) {
            $post[$categoryField] = $categoryId;
        }
        if ($authorId > 0) {
            $post[$authorField] = $authorId;
        }
        return \Phpcmf\Service::M()->table_site($module)->insert($post);
    }

    private function ciyun_recent_logs($limit)
    {
        $limit = max(1, min($limit, 200));
        $file = dirname(__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;
    }

    private 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]))) {
            $this->ciyun_log('unauthorized', '', 'Token error');
            $this->ciyun_response(401, ['success' => false, 'message' => 'Token error']);
        }
    }

    private 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)) {
            $this->ciyun_response(401, ['success' => false, 'message' => 'IP not allowed']);
        }
    }

    private function ciyun_validate($data)
    {
        if (empty($data['title']) || empty($data['content'])) {
            $this->ciyun_response(400, ['success' => false, 'message' => 'title and content are required']);
        }
        if ($this->ciyun_strlen($data['title']) > 200 || $this->ciyun_strlen($data['content']) > 200000) {
            $this->ciyun_response(400, ['success' => false, 'message' => 'title or content is too long']);
        }
    }

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

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

    private function ciyun_log($status, $title, $message)
    {
        $file = dirname(__DIR__) . '/publish.log';
        $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($file, $line, FILE_APPEND);
    }

    private 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;
    }
}
