<?php
namespace plugins\ciyun_publisher\controller;

use cmf\controller\PluginBaseController;
use think\Db;

class ApiController extends PluginBaseController
{
    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')]);
            }
            $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' => '发布成功']);
        } catch (\Throwable $e) {
            $this->ciyun_log('error', '', $e->getMessage());
            $this->ciyun_response(500, ['success' => false, 'message' => '服务器错误', 'error' => $e->getMessage()]);
        }
    }

    private function ciyun_config()
    {
        $config = function_exists('cmf_get_option') ? cmf_get_option('ciyun_publisher') : [];
        return [
            'token' => (string)($config['token'] ?? ''),
            'whitelist_ips' => (string)($config['whitelist_ips'] ?? ''),
            'force_draft' => (string)($config['force_draft'] ?? '1'),
        ];
    }

    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')),
                'authors' => count($this->ciyun_terms('author')),
                'force_draft' => ($config['force_draft'] ?? '1') === '1',
            ],
            'api' => '/plugin/ciyun_publisher/api/index',
            'version' => self::CIYUN_PUBLISHER_VERSION,
        ];
    }

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

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

    private function ciyun_categories()
    {
        try {
            $rows = Db::name('portal_category')->field('id,name')->select();
        } catch (\Throwable $e) {
            return [];
        }
        $items = [];
        foreach ($rows as $row) {
            $items[] = ['id' => intval($row['id']), 'name' => (string)$row['name']];
        }
        return $items;
    }

    private function ciyun_authors()
    {
        try {
            $rows = Db::name('user')->field('id,user_login,user_nickname')->select();
        } catch (\Throwable $e) {
            return [];
        }
        $items = [];
        foreach ($rows as $row) {
            $name = trim((string)($row['user_nickname'] ?: $row['user_login']));
            if (intval($row['id']) > 0 && $name !== '') {
                $items[] = ['id' => intval($row['id']), 'name' => $name];
            }
        }
        return $items;
    }

    private function ciyun_save_article($data, $config)
    {
        $isDraft = ($config['force_draft'] ?? '1') === '1' || ($data['status'] ?? 'draft') !== 'publish';
        $now = time();
        $post = [
            'post_author' => intval($data['author_id'] ?? 1),
            'post_keywords' => is_array($data['tags'] ?? null) ? implode(',', $data['tags']) : '',
            'post_source' => 'CiyunPublisher',
            'post_title' => $data['title'],
            'post_excerpt' => $data['excerpt'] ?? '',
            'post_content' => $data['content'],
            'post_status' => $isDraft ? 0 : 1,
            'comment_status' => 1,
            'create_time' => !empty($data['created_at']) ? strtotime($data['created_at']) : $now,
            'update_time' => $now,
            'published_time' => $isDraft ? 0 : $now,
            'post_type' => 1,
            'more' => '',
        ];
        $postId = Db::name('portal_post')->insertGetId($post);
        $categoryId = intval($data['category_id'] ?? 0);
        if ($categoryId > 0) {
            Db::name('portal_category_post')->insert(['post_id' => $postId, 'category_id' => $categoryId, 'list_order' => 10000, 'status' => 1]);
        }
        return $postId;
    }

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

    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 错误']);
        }
    }

    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 不在白名单']);
        }
    }

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

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

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

    private function ciyun_log($status, $title, $message)
    {
        $file = __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;
    }
}
