<?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'] ?? '') === 'GET' && ($_GET['action'] ?? '') === 'image') {
                $this->ciyun_serve_image($_GET['file'] ?? '');
            }
            if (strtoupper($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
                $this->ciyun_response(405, ['success' => false, 'message' => '仅支持 POST 请求']);
            }
            if (stripos($_SERVER['CONTENT_TYPE'] ?? '', 'application/json') === false) {
                $this->ciyun_response(400, ['success' => false, 'message' => '请求内容必须是 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' => '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')]);
            }
            if (($data['action'] ?? '') === 'upload_image') {
                $this->ciyun_response(200, $this->ciyun_upload_image($data));
            }
            $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' => '自检通过',
            '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_upload_image($data)
    {
        $raw = base64_decode((string)($data['data_base64'] ?? ''), true);
        if ($raw === false || $raw === '') {
            $this->ciyun_response(400, ['success' => false, 'message' => '图片内容无效']);
        }
        if (strlen($raw) > 5 * 1024 * 1024) {
            $this->ciyun_response(400, ['success' => false, 'message' => '图片超过 5MB']);
        }
        if ($this->ciyun_reject_non_image_content_type($data['content_type'] ?? '')) {
            $this->ciyun_response(400, ['success' => false, 'message' => '图片类型无效']);
        }
        $contentType = $this->ciyun_image_content_type($data['content_type'] ?? '', $data['filename'] ?? '');
        $extension = $this->ciyun_image_extension($contentType, $data['filename'] ?? '');
        $dir = __DIR__ . '/../uploads';
        if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
            $this->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) {
            $this->ciyun_response(500, ['success' => false, 'message' => '图片保存失败']);
        }
        return ['success' => true, 'url' => $this->ciyun_image_url($filename)];
    }

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

    private function ciyun_image_url($filename)
    {
        $scheme = $this->ciyun_request_scheme();
        $host = $_SERVER['HTTP_HOST'] ?? '';
        $uri = $_SERVER['REQUEST_URI'] ?? ($_SERVER['SCRIPT_NAME'] ?? '');
        $parts = parse_url($uri);
        $path = $parts['path'] ?? ($_SERVER['SCRIPT_NAME'] ?? '');
        $query = [];
        if (!empty($parts['query'])) {
            parse_str($parts['query'], $query);
        }
        $query['action'] = 'image';
        $query['file'] = $filename;
        return $scheme . '://' . $host . $path . '?' . http_build_query($query);
    }

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

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

    private function ciyun_image_extension($contentType, $filename = '')
    {
        $contentType = $this->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';
    }

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

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