<?php

declare(strict_types=1);

namespace Admin\Controllers;

/**
 * Admin Blog Controller
 *
 * Full CRUD for blog posts with:
 * - Rich text content
 * - Featured image + OG image upload
 * - Category & tags
 * - SEO meta fields (title, description, keywords)
 * - Publish/Draft toggle
 * - Slug auto-generation from title
 */
class AdminBlogController extends AdminController
{
    /**
     * List all blog posts with optional category filter.
     */
    public function index(array $params = []): void
    {
        requireAdmin();

        $category = trim($_GET['category'] ?? '');
        $search   = trim($_GET['search'] ?? '');
        $status   = trim($_GET['status'] ?? '');

        // Build query with filters
        $where = '1=1';
        $queryParams = [];

        if ($category !== '') {
            $where .= ' AND bp.category = :category';
            $queryParams[':category'] = $category;
        }

        if ($search !== '') {
            $where .= ' AND (bp.title LIKE :search OR bp.short_description LIKE :search2)';
            $queryParams[':search'] = '%' . $search . '%';
            $queryParams[':search2'] = '%' . $search . '%';
        }

        if ($status === 'published') {
            $where .= ' AND bp.is_published = 1';
        } elseif ($status === 'draft') {
            $where .= ' AND bp.is_published = 0';
        }

        $sql = sprintf(
            'SELECT bp.*, u.name AS author_name
             FROM `blog_posts` bp
             LEFT JOIN `users` u ON bp.author_id = u.id
             WHERE %s
             ORDER BY bp.created_at DESC',
            $where
        );

        $stmt = $this->db->prepare($sql);
        $stmt->execute($queryParams);
        $posts = $stmt->fetchAll() ?: [];

        // Get categories for filter
        $catStmt = $this->db->query('SELECT * FROM `blog_categories` ORDER BY `sort_order` ASC, `name` ASC');
        $categories = $catStmt->fetchAll() ?: [];

        // Also get distinct categories from blog_posts (for posts using old category values)
        $usedCatStmt = $this->db->query('SELECT DISTINCT `category` FROM `blog_posts` WHERE `category` IS NOT NULL AND `category` != "" ORDER BY `category` ASC');
        $usedCategories = $usedCatStmt->fetchAll() ?: [];

        $this->adminView('blog_posts', [
            'title'          => 'Manage Blog Posts',
            'currentPage'    => 'blog_posts',
            'posts'          => $posts,
            'categories'     => $categories,
            'usedCategories' => $usedCategories,
            'editPost'       => null,
            'filterCategory' => $category,
            'filterSearch'   => $search,
            'filterStatus'   => $status,
        ]);
    }

    /**
     * Show the create blog post form.
     */
    public function create(array $params = []): void
    {
        requireAdmin();

        $catStmt = $this->db->query('SELECT * FROM `blog_categories` ORDER BY `sort_order` ASC, `name` ASC');
        $categories = $catStmt->fetchAll() ?: [];

        $this->adminView('blog_posts', [
            'title'          => 'Add New Blog Post',
            'currentPage'    => 'blog_posts',
            'posts'          => [],
            'categories'     => $categories,
            'usedCategories' => [],
            'editPost'       => null,
            'showForm'       => true,
        ]);
    }

    /**
     * Store a new blog post.
     */
    public function store(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $title            = sanitize($_POST['title'] ?? '');
        $slug             = sanitize($_POST['slug'] ?? '');
        $shortDescription = sanitize($_POST['short_description'] ?? '');
        $content          = $_POST['content'] ?? ''; // Don't sanitize — contains HTML from rich editor
        $category         = sanitize($_POST['category'] ?? '');
        $tags             = sanitize($_POST['tags'] ?? '');
        $isPublished      = isset($_POST['is_published']) ? 1 : 0;
        $publishedAt      = sanitize($_POST['published_at'] ?? '');
        $metaTitle        = sanitize($_POST['meta_title'] ?? '');
        $metaDescription  = sanitize($_POST['meta_description'] ?? '');
        $metaKeywords     = sanitize($_POST['meta_keywords'] ?? '');

        if (empty($title)) {
            flash('error', 'Blog post title is required.');
            redirect(BASE_PATH . '/admin/blog-posts/create');
        }

        // Auto-generate slug if empty
        if (empty($slug)) {
            $slug = $this->generateSlug($title);
        } else {
            $slug = $this->sanitizeSlug($slug);
        }

        // Ensure slug is unique
        $slug = $this->ensureUniqueSlug($slug);

        // Handle featured image upload
        $imagePath = $this->handleImageUpload('image', 'blogs');

        // Handle OG image upload
        $ogImagePath = $this->handleImageUpload('og_image', 'blogs');

        // Get current user as author
        $user = getCurrentUser();
        $authorId = $user !== null ? (int) $user['id'] : null;

        // Set published_at to now if publishing and no date set
        if ($isPublished && empty($publishedAt)) {
            $publishedAt = date('Y-m-d H:i:s');
        }

        $stmt = $this->db->prepare(
            'INSERT INTO `blog_posts`
                (`title`, `slug`, `short_description`, `content`, `image`, `category`, `tags`,
                 `author_id`, `is_published`, `published_at`,
                 `meta_title`, `meta_description`, `meta_keywords`, `og_image`)
             VALUES
                (:title, :slug, :short_description, :content, :image, :category, :tags,
                 :author_id, :is_published, :published_at,
                 :meta_title, :meta_description, :meta_keywords, :og_image)'
        );

        $stmt->execute([
            ':title'             => $title,
            ':slug'              => $slug,
            ':short_description' => $shortDescription ?: null,
            ':content'           => $content ?: null,
            ':image'             => $imagePath,
            ':category'          => $category ?: null,
            ':tags'              => $tags ?: null,
            ':author_id'         => $authorId,
            ':is_published'      => $isPublished,
            ':published_at'      => $publishedAt ?: null,
            ':meta_title'        => $metaTitle ?: null,
            ':meta_description'  => $metaDescription ?: null,
            ':meta_keywords'     => $metaKeywords ?: null,
            ':og_image'          => $ogImagePath,
        ]);

        flash('success', 'Blog post created successfully.');
        redirect(BASE_PATH . '/admin/blog-posts');
    }

    /**
     * Show the edit blog post form.
     */
    public function edit(array $params = []): void
    {
        requireAdmin();

        $id = (int) ($params['id'] ?? 0);

        $stmt = $this->db->prepare('SELECT * FROM `blog_posts` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $editPost = $stmt->fetch() ?: null;

        if ($editPost === null) {
            flash('error', 'Blog post not found.');
            redirect(BASE_PATH . '/admin/blog-posts');
        }

        $catStmt = $this->db->query('SELECT * FROM `blog_categories` ORDER BY `sort_order` ASC, `name` ASC');
        $categories = $catStmt->fetchAll() ?: [];

        $this->adminView('blog_posts', [
            'title'          => 'Edit Blog Post',
            'currentPage'    => 'blog_posts',
            'posts'          => [],
            'categories'     => $categories,
            'usedCategories' => [],
            'editPost'       => $editPost,
            'showForm'       => true,
        ]);
    }

    /**
     * Update an existing blog post.
     */
    public function update(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);

        $stmt = $this->db->prepare('SELECT * FROM `blog_posts` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $post = $stmt->fetch() ?: null;

        if ($post === null) {
            flash('error', 'Blog post not found.');
            redirect(BASE_PATH . '/admin/blog-posts');
        }

        $title            = sanitize($_POST['title'] ?? '');
        $slug             = sanitize($_POST['slug'] ?? '');
        $shortDescription = sanitize($_POST['short_description'] ?? '');
        $content          = $_POST['content'] ?? '';
        $category         = sanitize($_POST['category'] ?? '');
        $tags             = sanitize($_POST['tags'] ?? '');
        $isPublished      = isset($_POST['is_published']) ? 1 : 0;
        $publishedAt      = sanitize($_POST['published_at'] ?? '');
        $metaTitle        = sanitize($_POST['meta_title'] ?? '');
        $metaDescription  = sanitize($_POST['meta_description'] ?? '');
        $metaKeywords     = sanitize($_POST['meta_keywords'] ?? '');

        if (empty($title)) {
            flash('error', 'Blog post title is required.');
            redirect(BASE_PATH . '/admin/blog-posts/' . $id . '/edit');
        }

        // Auto-generate slug if empty
        if (empty($slug)) {
            $slug = $this->generateSlug($title);
        } else {
            $slug = $this->sanitizeSlug($slug);
        }

        // Ensure slug is unique (exclude current post)
        $slug = $this->ensureUniqueSlug($slug, $id);

        // Handle featured image replacement
        $imagePath = $this->handleImageUpload('image', 'blogs');
        if ($imagePath !== null) {
            $this->deleteImageFile($post['image'] ?? null);
        } else {
            $imagePath = $post['image'] ?? null;
        }

        // Handle OG image replacement
        $ogImagePath = $this->handleImageUpload('og_image', 'blogs');
        if ($ogImagePath !== null) {
            $this->deleteImageFile($post['og_image'] ?? null);
        } else {
            $ogImagePath = $post['og_image'] ?? null;
        }

        // Set published_at: if newly publishing and no date set
        if ($isPublished && empty($publishedAt) && empty($post['published_at'])) {
            $publishedAt = date('Y-m-d H:i:s');
        } elseif (!$isPublished) {
            $publishedAt = null; // Unpublishing
        } elseif (empty($publishedAt)) {
            $publishedAt = $post['published_at']; // Keep existing
        }

        $stmt = $this->db->prepare(
            'UPDATE `blog_posts` SET
                `title` = :title, `slug` = :slug, `short_description` = :short_description,
                `content` = :content, `image` = :image, `category` = :category, `tags` = :tags,
                `is_published` = :is_published, `published_at` = :published_at,
                `meta_title` = :meta_title, `meta_description` = :meta_description,
                `meta_keywords` = :meta_keywords, `og_image` = :og_image
             WHERE `id` = :id'
        );

        $stmt->execute([
            ':title'             => $title,
            ':slug'              => $slug,
            ':short_description' => $shortDescription ?: null,
            ':content'           => $content ?: null,
            ':image'             => $imagePath,
            ':category'          => $category ?: null,
            ':tags'              => $tags ?: null,
            ':is_published'      => $isPublished,
            ':published_at'      => $publishedAt,
            ':meta_title'        => $metaTitle ?: null,
            ':meta_description'  => $metaDescription ?: null,
            ':meta_keywords'     => $metaKeywords ?: null,
            ':og_image'          => $ogImagePath,
            ':id'                => $id,
        ]);

        flash('success', 'Blog post updated successfully.');
        redirect(BASE_PATH . '/admin/blog-posts');
    }

    /**
     * Delete a blog post.
     */
    public function delete(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);

        $stmt = $this->db->prepare('SELECT * FROM `blog_posts` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $post = $stmt->fetch() ?: null;

        if ($post !== null) {
            $this->deleteImageFile($post['image'] ?? null);
            $this->deleteImageFile($post['og_image'] ?? null);
        }

        $stmt = $this->db->prepare('DELETE FROM `blog_posts` WHERE `id` = :id');
        $stmt->execute([':id' => $id]);

        if ($stmt->rowCount() > 0) {
            flash('success', 'Blog post deleted successfully.');
        } else {
            flash('warning', 'Blog post not found or already deleted.');
        }
        redirect(BASE_PATH . '/admin/blog-posts');
    }

    /**
     * Toggle publish status (AJAX or form POST).
     */
    public function togglePublish(array $params = []): void
    {
        requireAdmin();
        $this->validateCsrf();

        $id = (int) ($params['id'] ?? 0);

        $stmt = $this->db->prepare('SELECT `id`, `is_published`, `published_at` FROM `blog_posts` WHERE `id` = :id LIMIT 1');
        $stmt->execute([':id' => $id]);
        $post = $stmt->fetch() ?: null;

        if ($post === null) {
            flash('error', 'Blog post not found.');
            redirect(BASE_PATH . '/admin/blog-posts');
        }

        $newStatus = $post['is_published'] ? 0 : 1;
        $publishedAt = $post['published_at'];

        // Set published_at when first publishing
        if ($newStatus && empty($publishedAt)) {
            $publishedAt = date('Y-m-d H:i:s');
        }

        // If unpublishing, keep published_at (so it can be re-published)
        $updateStmt = $this->db->prepare(
            'UPDATE `blog_posts` SET `is_published` = :status, `published_at` = :published_at WHERE `id` = :id'
        );
        $updateStmt->execute([
            ':status'       => $newStatus,
            ':published_at' => $publishedAt,
            ':id'           => $id,
        ]);

        flash('success', $newStatus ? 'Blog post published.' : 'Blog post unpublished (draft).');
        redirect(BASE_PATH . '/admin/blog-posts');
    }

    /**
     * Generate a URL-friendly slug from a title.
     */
    private function generateSlug(string $title): string
    {
        $slug = strtolower($title);
        $slug = preg_replace('/[^a-z0-9\s-]/', '', $slug);
        $slug = preg_replace('/[\s-]+/', '-', $slug);
        $slug = trim($slug, '-');
        return $slug;
    }

    /**
     * Sanitize a user-provided slug.
     */
    private function sanitizeSlug(string $slug): string
    {
        $slug = strtolower($slug);
        $slug = preg_replace('/[^a-z0-9\s-]/', '', $slug);
        $slug = preg_replace('/[\s-]+/', '-', $slug);
        $slug = trim($slug, '-');
        return $slug;
    }

    /**
     * Ensure slug is unique. Append -2, -3, etc. if needed.
     *
     * @param string $slug The desired slug
     * @param int|null $excludeId Post ID to exclude from uniqueness check (for updates)
     * @return string A unique slug
     */
    private function ensureUniqueSlug(string $slug, ?int $excludeId = null): string
    {
        $originalSlug = $slug;
        $counter = 2;

        while (true) {
            $sql = 'SELECT COUNT(*) AS cnt FROM `blog_posts` WHERE `slug` = :slug';
            $params = [':slug' => $slug];

            if ($excludeId !== null) {
                $sql .= ' AND `id` != :exclude_id';
                $params[':exclude_id'] = $excludeId;
            }

            $stmt = $this->db->prepare($sql);
            $stmt->execute($params);
            $count = (int) ($stmt->fetch()['cnt'] ?? 0);

            if ($count === 0) {
                return $slug;
            }

            $slug = $originalSlug . '-' . $counter;
            $counter++;
        }
    }
}
