<?php
/**
 * ZLO Platform - Blog Controller
 */

declare(strict_types=1);

require_once __DIR__ . '/../core/Model.php';
require_once __DIR__ . '/../core/Router.php';

class BlogController
{
    private Database $db;
    
    public function __construct()
    {
        $this->db = new Database();
    }
    
    /**
     * Get all blog posts
     */
    public function index(array $params): array
    {
        $query = Router::getQuery();
        
        $page = (int) ($query['page'] ?? 1);
        $limit = (int) ($query['limit'] ?? 10);
        $category = $query['category'] ?? null;
        $search = $query['search'] ?? null;
        
        $sql = "SELECT bp.*, bc.name as category_name, bc.slug as category_slug, u.name as author_name 
                FROM blog_posts bp 
                LEFT JOIN blog_categories bc ON bp.category_id = bc.id 
                LEFT JOIN users u ON bp.author_id = u.id 
                WHERE bp.status = 'published' AND bp.published_at <= NOW()";
        
        $params = [];
        
        if ($category) {
            $sql .= " AND bc.slug = ?";
            $params[] = $category;
        }
        
        if ($search) {
            $sql .= " AND (bp.title LIKE ? OR bp.excerpt LIKE ? OR bp.content LIKE ?)";
            $searchTerm = "%{$search}%";
            $params[] = $searchTerm;
            $params[] = $searchTerm;
            $params[] = $searchTerm;
        }
        
        $sql .= " ORDER BY bp.published_at DESC";
        
        // Count total for pagination
        $countSql = str_replace("SELECT bp.*, bc.name as category_name, bc.slug as category_slug, u.name as author_name", "SELECT COUNT(*) as total", $sql);
        $countSql = preg_replace('/ORDER BY.*$/', '', $countSql);
        $totalResult = $this->db->fetchOne($countSql, $params);
        $total = (int) ($totalResult['total'] ?? 0);
        
        // Add pagination
        $offset = ($page - 1) * $limit;
        $sql .= " LIMIT ? OFFSET ?";
        $params[] = $limit;
        $params[] = $offset;
        
        $posts = $this->db->fetchAll($sql, $params);
        
        // Parse tags JSON
        foreach ($posts as &$post) {
            $post['tags'] = json_decode($post['tags'] ?? '[]', true);
        }
        
        return [
            'posts' => $posts,
            'pagination' => [
                'current_page' => $page,
                'per_page' => $limit,
                'total' => $total,
                'last_page' => (int) ceil($total / $limit),
                'from' => $offset + 1,
                'to' => min($offset + $limit, $total)
            ]
        ];
    }
    
    /**
     * Get single blog post
     */
    public function show(array $params): ?array
    {
        $slug = $params['slug'] ?? '';
        
        if (!$slug) {
            http_response_code(400);
            return ['error' => 'Slug is required'];
        }
        
        $sql = "SELECT bp.*, bc.name as category_name, bc.slug as category_slug, u.name as author_name, u.avatar as author_avatar 
                FROM blog_posts bp 
                LEFT JOIN blog_categories bc ON bp.category_id = bc.id 
                LEFT JOIN users u ON bp.author_id = u.id 
                WHERE bp.slug = ? AND bp.status = 'published'";
        
        $post = $this->db->fetchOne($sql, [$slug]);
        
        if (!$post) {
            http_response_code(404);
            return ['error' => 'Post not found'];
        }
        
        // Increment views
        $this->db->query("UPDATE blog_posts SET views = views + 1 WHERE id = ?", [$post['id']]);
        
        // Parse tags
        $post['tags'] = json_decode($post['tags'] ?? '[]', true);
        
        // Get related posts
        $sql = "SELECT bp.id, bp.title, bp.slug, bp.featured_image, bp.published_at 
                FROM blog_posts bp 
                WHERE bp.category_id = ? AND bp.id != ? AND bp.status = 'published' 
                ORDER BY bp.published_at DESC LIMIT 3";
        $post['related_posts'] = $this->db->fetchAll($sql, [$post['category_id'], $post['id']]);
        
        return $post;
    }
    
    /**
     * Get blog categories
     */
    public function categories(array $params): array
    {
        $sql = "SELECT bc.*, COUNT(bp.id) as post_count 
                FROM blog_categories bc 
                LEFT JOIN blog_posts bp ON bc.id = bp.category_id AND bp.status = 'published' 
                GROUP BY bc.id 
                ORDER BY bc.name";
        
        return $this->db->fetchAll($sql);
    }
    
    /**
     * Create blog post (admin)
     */
    public function create(array $params): array
    {
        AuthController::requirePermission('blog.create');
        
        $body = Router::getBody();
        $security = new Security();
        
        // Validate required fields
        $required = ['title', 'content', 'category_id'];
        foreach ($required as $field) {
            if (empty($body[$field])) {
                http_response_code(400);
                return ['error' => "Field {$field} is required"];
            }
        }
        
        // Generate slug
        $body['slug'] = $this->generateSlug($body['title']);
        
        // Set author
        $user = (new AuthController())->getAuthenticatedUser();
        $body['author_id'] = $user['id'];
        
        // Parse tags
        if (!empty($body['tags']) && is_array($body['tags'])) {
            $body['tags'] = json_encode($body['tags']);
        }
        
        // Set published date if publishing
        if ($body['status'] === 'published') {
            $body['published_at'] = date('Y-m-d H:i:s');
        }
        
        try {
            $id = $this->db->insert('blog_posts', $body);
            
            // Update category post count
            $this->db->query("UPDATE blog_categories SET post_count = post_count + 1 WHERE id = ?", [$body['category_id']]);
            
            http_response_code(201);
            return $this->getPostById($id);
        } catch (Exception $e) {
            http_response_code(500);
            return ['error' => 'Failed to create post'];
        }
    }
    
    /**
     * Update blog post (admin)
     */
    public function update(array $params): ?array
    {
        AuthController::requirePermission('blog.edit');
        
        $id = (int) ($params['id'] ?? 0);
        
        if (!$id) {
            http_response_code(400);
            return ['error' => 'Post ID is required'];
        }
        
        $body = Router::getBody();
        
        // Parse tags
        if (!empty($body['tags']) && is_array($body['tags'])) {
            $body['tags'] = json_encode($body['tags']);
        }
        
        // Update slug if title changed
        if (!empty($body['title'])) {
            $body['slug'] = $this->generateSlug($body['title'], $id);
        }
        
        // Set published date if publishing for first time
        if (!empty($body['status']) && $body['status'] === 'published') {
            $existing = $this->getPostById($id);
            if ($existing && !$existing['published_at']) {
                $body['published_at'] = date('Y-m-d H:i:s');
            }
        }
        
        try {
            $this->db->update('blog_posts', $body, "id = ?", [$id]);
            return $this->getPostById($id);
        } catch (Exception $e) {
            http_response_code(500);
            return ['error' => 'Failed to update post'];
        }
    }
    
    /**
     * Delete blog post (admin)
     */
    public function delete(array $params): array
    {
        AuthController::requirePermission('blog.delete');
        
        $id = (int) ($params['id'] ?? 0);
        
        if (!$id) {
            http_response_code(400);
            return ['error' => 'Post ID is required'];
        }
        
        try {
            // Get category_id before deleting
            $post = $this->getPostById($id);
            
            $this->db->delete('blog_posts', "id = ?", [$id]);
            
            // Update category post count
            if ($post && $post['category_id']) {
                $this->db->query("UPDATE blog_categories SET post_count = post_count - 1 WHERE id = ?", [$post['category_id']]);
            }
            
            return ['message' => 'Post deleted successfully'];
        } catch (Exception $e) {
            http_response_code(500);
            return ['error' => 'Failed to delete post'];
        }
    }
    
    /**
     * Get post by ID
     */
    private function getPostById(int $id): ?array
    {
        $sql = "SELECT bp.*, bc.name as category_name, u.name as author_name 
                FROM blog_posts bp 
                LEFT JOIN blog_categories bc ON bp.category_id = bc.id 
                LEFT JOIN users u ON bp.author_id = u.id 
                WHERE bp.id = ?";
        
        return $this->db->fetchOne($sql, [$id]);
    }
    
    /**
     * Generate unique slug
     */
    private function generateSlug(string $title, ?int $excludeId = null): string
    {
        $slug = $this->slugify($title);
        $originalSlug = $slug;
        $counter = 1;
        
        while (true) {
            $sql = "SELECT id FROM blog_posts WHERE slug = ?";
            $params = [$slug];
            
            if ($excludeId) {
                $sql .= " AND id != ?";
                $params[] = $excludeId;
            }
            
            $existing = $this->db->fetchOne($sql, $params);
            
            if (!$existing) {
                break;
            }
            
            $slug = $originalSlug . '-' . $counter;
            $counter++;
        }
        
        return $slug;
    }
    
    /**
     * Convert title to slug
     */
    private function slugify(string $text): string
    {
        $text = preg_replace('~[^\pL\d]+~u', '-', $text);
        $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
        $text = preg_replace('~[^-\w]+~', '', $text);
        $text = trim($text, '-');
        $text = preg_replace('~-+~', '-', $text);
        $text = strtolower($text);
        
        return $text ?: 'n-a';
    }
}
