<?php

namespace App\Http\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Models\BlogPost;
use App\Models\BlogCategory;
use App\Models\Menu;
use App\Models\Page;

class BlogController extends Controller
{
    private const POSTS_PER_PAGE = 12;

    public function index(Request $request, array $params = []): void
    {
        $currentPage = max(1, (int) ($request->query('page') ?? 1));
        $perPage     = self::POSTS_PER_PAGE;
        $offset      = ($currentPage - 1) * $perPage;

        $total      = BlogPost::publishedCount();
        $totalPages = max(1, (int) ceil($total / $perPage));
        $currentPage = min($currentPage, $totalPages);
        $offset     = ($currentPage - 1) * $perPage;

        $posts      = BlogPost::published($perPage, $offset);
        $categories = BlogCategory::allWithPostCount();

        // Load associated page record for editable intro content, show_title, SEO
        $page = Page::findByType('blog');
        if (!$page) {
            $page = Page::findBySlug('blog');
        }
        $pageTitle = ($page['title'] ?? '') ?: __('theme.blog_title');

        $this->renderFrontend('blog-list', [
            'system_page'     => $page ?: ['title' => __('theme.blog_title'), 'content' => '', 'show_title' => 1],
            'page_title'      => $pageTitle,
            'seo_title'       => ($page['seo_title'] ?? '') ?: $pageTitle . ' – ' . setting('site_name'),
            'seo_description' => $page['seo_description'] ?? '',
            'canonical_url'   => base_url('/blog'),
            'breadcrumbs'     => [
                ['label' => 'Home',     'url' => '/'],
                ['label' => $pageTitle, 'url' => null],
            ],
            'posts'           => $posts,
            'categories'      => $categories,
            'pagination'      => [
                'current_page' => $currentPage,
                'total_pages'  => $totalPages,
                'total_posts'  => $total,
                'base_url'     => '/blog',
            ],
            'current_uri'     => '/blog',
        ]);
    }

    public function show(Request $request, array $params = []): void
    {
        $slug = $params['slug'] ?? '';
        $post = BlogPost::findWithDetails($slug);

        if (!$post) {
            http_response_code(404);
            $this->renderFrontend('404', ['current_uri' => $request->uri()]);
            return;
        }

        // HTTP cache headers (ETag, Last-Modified, 304 support)
        $this->sendContentCacheHeaders($post['updated_at'] ?? '', $post['slug'] ?? '');

        // OG image: per-post override takes priority, then featured image
        $ogImage = '';
        if (!empty($post['og_image'])) {
            $ogImage = $post['og_image'];
        } elseif (!empty($post['featured_image'])) {
            $webpUrl = webp_url($post['featured_image']);
            $ogImage = base_url($webpUrl ?? ('/uploads/' . $post['featured_image']));
        }

        // Load page builder sections if enabled
        $sections = [];
        if (!empty($post['pagebuilder_enabled'])) {
            $sections = \App\Models\PageSection::active('blog:' . $post['id']);
        }

        // F3: Reading time
        $readingTime = 0;
        if (setting('blog_reading_time', '1') === '1') {
            $wordCount   = str_word_count(strip_tags($post['content'] ?? ''));
            $readingTime = max(1, (int) ceil($wordCount / 200));
        }

        // F3: Table of Contents (modifies $post['content'] to add IDs to headings)
        $toc = [];
        if (setting('blog_toc', '1') === '1' && !empty($post['content'])) {
            $post['content'] = $this->buildToc($post['content'], $toc);
        }

        // F3: Related posts
        $relatedPosts = [];
        if (setting('blog_related_posts', '1') === '1') {
            $relatedPosts = $this->getRelatedPosts((int) $post['id'], (int) ($post['category_id'] ?? 0));
        }

        $this->renderFrontend('blog-single', [
            'post'            => $post,
            'sections'        => $sections,
            'reading_time'    => $readingTime,
            'toc'             => $toc,
            'related_posts'   => $relatedPosts,
            'page_title'      => $post['title'],
            'seo_title'       => $post['seo_title'] ?: $post['title'] . ' – ' . setting('site_name'),
            'seo_description' => $post['seo_description'] ?? $post['excerpt'] ?? '',
            'canonical_url'   => !empty($post['canonical_url']) ? $post['canonical_url'] : base_url('/blog/' . $slug),
            'og_type'         => 'article',
            'og_image'        => $ogImage,
            'robots_meta'     => $post['robots_meta'] ?? '',
            'custom_css'      => $post['custom_css'] ?? '',
            'custom_js'       => $post['custom_js'] ?? '',
            'breadcrumbs'     => [
                ['label' => 'Home',         'url' => '/'],
                ['label' => 'Blog',         'url' => '/blog'],
                ['label' => $post['title'], 'url' => null],
            ],
            'current_uri'     => '/blog/' . $slug,
        ]);
    }

    public function category(Request $request, array $params = []): void
    {
        $slug = $params['slug'] ?? '';
        $category = BlogCategory::findBySlug($slug);

        if (!$category) {
            http_response_code(404);
            $this->renderFrontend('404', ['current_uri' => $request->uri()]);
            return;
        }

        $page    = max(1, (int) ($request->query('page') ?? 1));
        $perPage = self::POSTS_PER_PAGE;

        $total      = BlogPost::publishedCountByCategory((int) $category['id']);
        $totalPages = max(1, (int) ceil($total / $perPage));
        $page       = min($page, $totalPages);
        $offset     = ($page - 1) * $perPage;

        $posts      = BlogPost::publishedByCategory((int) $category['id'], $perPage, $offset);
        $categories = BlogCategory::allWithPostCount();

        // Load system page for show_title / intro content
        $systemPage = Page::findByType('blog') ?: Page::findBySlug('blog');

        $this->renderFrontend('blog-list', [
            'system_page'     => $systemPage ?: ['title' => 'Blog', 'content' => '', 'show_title' => 1],
            'page_title'      => $category['name'],
            'seo_title'       => $category['name'] . ' – Blog – ' . setting('site_name'),
            'canonical_url'   => base_url('/blog/category/' . $slug),
            'breadcrumbs'     => [
                ['label' => 'Home',            'url' => '/'],
                ['label' => 'Blog',            'url' => '/blog'],
                ['label' => $category['name'], 'url' => null],
            ],
            'posts'           => $posts,
            'categories'      => $categories,
            'active_category' => $slug,
            'pagination'      => [
                'current_page' => $page,
                'total_pages'  => $totalPages,
                'total_posts'  => $total,
                'base_url'     => '/blog/category/' . $slug,
            ],
            'current_uri'     => '/blog/category/' . $slug,
        ]);
    }

    public function tag(Request $request, array $params = []): void
    {
        $slug = $params['slug'] ?? '';

        $posts = $this->db()->fetchAll(
            "SELECT p.*, u.username as author_name FROM iw_blog_posts p
             LEFT JOIN iw_blog_post_tags pt ON p.id = pt.post_id
             LEFT JOIN iw_blog_tags t ON pt.tag_id = t.id
             LEFT JOIN iw_users u ON p.author_id = u.id
             WHERE ((p.status = 'published' AND (p.unpublish_at IS NULL OR p.unpublish_at > NOW()))
                 OR (p.status = 'scheduled' AND p.publish_at IS NOT NULL AND p.publish_at <= NOW()
                     AND (p.unpublish_at IS NULL OR p.unpublish_at > NOW())))
               AND t.slug = :tag_slug
             ORDER BY COALESCE(p.published_at, p.publish_at) DESC",
            ['tag_slug' => $slug]
        );

        $tagLabel = 'Tag: ' . $slug;

        // Load system page for show_title / intro content
        $systemPage = Page::findByType('blog') ?: Page::findBySlug('blog');

        $this->renderFrontend('blog-list', [
            'system_page'     => $systemPage ?: ['title' => 'Blog', 'content' => '', 'show_title' => 1],
            'page_title'      => $tagLabel,
            'seo_title'       => $tagLabel . ' – Blog – ' . setting('site_name'),
            'seo_description' => '',
            'canonical_url'   => base_url('/blog/tag/' . $slug),
            'breadcrumbs'     => [
                ['label' => 'Home',     'url' => '/'],
                ['label' => 'Blog',     'url' => '/blog'],
                ['label' => $tagLabel,  'url' => null],
            ],
            'posts'           => $posts,
            'current_uri'     => '/blog/tag/' . $slug,
        ]);
    }

    /**
     * Parse H2/H3 headings, inject IDs, return structured ToC array.
     * Modifies $content by reference (adds id="" attributes to headings).
     */
    private function buildToc(string $content, array &$toc): string
    {
        $usedIds = [];

        $content = preg_replace_callback(
            '/<(h[23])([^>]*)>(.*?)<\/h[23]>/is',
            function (array $m) use (&$toc, &$usedIds): string {
                $tag   = $m[1];
                $attrs = $m[2];
                $inner = $m[3];
                $level = (int) substr($tag, 1);
                $text  = trim(strip_tags($inner));

                // Check for existing id attribute
                if (preg_match('/\bid=["\']([^"\']+)["\']/', $attrs, $idMatch)) {
                    $id = $idMatch[1];
                } else {
                    // Generate slug-based id
                    $id = slugify($text);
                    if ($id === '') {
                        $id = 'heading-' . (count($toc) + 1);
                    }
                    // Ensure uniqueness
                    if (isset($usedIds[$id])) {
                        $usedIds[$id]++;
                        $id .= '-' . $usedIds[$id];
                    } else {
                        $usedIds[$id] = 1;
                    }
                    $attrs .= ' id="' . htmlspecialchars($id, ENT_QUOTES, 'UTF-8') . '"';
                }

                $toc[] = ['id' => $id, 'text' => $text, 'level' => $level];

                return '<' . $tag . $attrs . '>' . $inner . '</' . $tag . '>';
            },
            $content
        );

        return $content;
    }

    /**
     * Find up to 3 related published posts from the same category, excluding current post.
     */
    private function getRelatedPosts(int $postId, int $categoryId): array
    {
        $visibleWhere = "(status = 'published' AND (unpublish_at IS NULL OR unpublish_at > NOW()))
            OR (status = 'scheduled' AND publish_at IS NOT NULL AND publish_at <= NOW()
                AND (unpublish_at IS NULL OR unpublish_at > NOW()))";

        if ($categoryId > 0) {
            $related = $this->db()->fetchAll(
                "SELECT id, title, slug, featured_image, published_at, created_at
                 FROM iw_blog_posts
                 WHERE ({$visibleWhere})
                   AND id != :pid
                   AND category_id = :cid
                 ORDER BY COALESCE(published_at, publish_at) DESC
                 LIMIT 3",
                ['pid' => $postId, 'cid' => $categoryId]
            );
            if (!empty($related)) {
                return $related;
            }
        }

        // Fallback: any recent published posts
        return $this->db()->fetchAll(
            "SELECT id, title, slug, featured_image, published_at, created_at
             FROM iw_blog_posts
             WHERE ({$visibleWhere})
               AND id != :pid
             ORDER BY COALESCE(published_at, publish_at) DESC
             LIMIT 3",
            ['pid' => $postId]
        );
    }

    private function renderFrontend(string $template, array $data = []): void
    {
        $data['main_menu']      = Menu::getItems('main');
        $data['main_menu_tree'] = Menu::getItemsTree('main');
        $data['footer_menu']    = Menu::getItems('footer');

        $view = $this->app->service('view');
        $html = $view->render($template, $data);
        Response::html($html);
    }
}
