<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;

/**
 * PublishingPage Model
 *
 * Represents a dynamic CMS page with JSON-based content blocks.
 * Supports flexible page building with various block types.
 *
 * @property int $id
 * @property string $title
 * @property string $slug
 * @property array|null $content_blocks
 * @property array|null $theme_colors
 * @property array|null $seo_meta
 * @property string $layout
 * @property bool $show_breadcrumbs
 * @property bool $show_sidebar
 * @property bool $is_published
 * @property \Carbon\Carbon|null $published_at
 * @property int|null $created_by
 * @property int|null $updated_by
 * @property int $view_count
 *
 * Requirements: 4.1, 4.2, 4.5, 10.2, 10.3
 */
class PublishingPage extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'title',
        'slug',
        'content_blocks',
        'theme_colors',
        'seo_meta',
        'layout',
        'show_breadcrumbs',
        'show_sidebar',
        'is_published',
        'published_at',
        'created_by',
        'updated_by',
        'view_count',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'content_blocks' => 'array',
        'theme_colors' => 'array',
        'seo_meta' => 'array',
        'show_breadcrumbs' => 'boolean',
        'show_sidebar' => 'boolean',
        'is_published' => 'boolean',
        'published_at' => 'datetime',
        'view_count' => 'integer',
    ];

    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'is_published' => false,
        'layout' => 'default',
        'show_breadcrumbs' => true,
        'show_sidebar' => false,
        'view_count' => 0,
    ];

    // =========================================================================
    // RELATIONSHIPS
    // =========================================================================

    /**
     * Get the user who created this page.
     */
    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * Get the user who last updated this page.
     */
    public function updater(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    // =========================================================================
    // SCOPES
    // =========================================================================

    /**
     * Scope a query to only include published pages.
     */
    public function scopePublished($query)
    {
        return $query->where('is_published', true);
    }

    /**
     * Scope a query to find by slug.
     */
    public function scopeBySlug($query, string $slug)
    {
        return $query->where('slug', $slug);
    }

    /**
     * Scope to order by latest.
     */
    public function scopeLatest($query)
    {
        return $query->orderBy('created_at', 'desc');
    }

    // =========================================================================
    // ACCESSORS & MUTATORS
    // =========================================================================

    /**
     * Set the slug attribute.
     */
    public function setSlugAttribute($value)
    {
        $this->attributes['slug'] = $value ?? Str::slug($this->attributes['title'] ?? '');
    }

    /**
     * Get the meta title for SEO.
     */
    public function getMetaTitleAttribute(): string
    {
        return $this->seo_meta['meta_title'] ?? $this->title;
    }

    /**
     * Get the meta description for SEO.
     */
    public function getMetaDescriptionAttribute(): string
    {
        return $this->seo_meta['meta_description'] ?? Str::limit(strip_tags($this->getFirstTextBlock()), 160);
    }

    /**
     * Get the keywords for SEO.
     */
    public function getKeywordsAttribute(): array
    {
        return $this->seo_meta['keywords'] ?? [];
    }

    /**
     * Get the Open Graph image.
     */
    public function getOgImageAttribute(): ?string
    {
        $ogImage = $this->seo_meta['og_image'] ?? null;
        if ($ogImage) {
            return asset('storage/' . $ogImage);
        }
        return null;
    }

    /**
     * Get the primary theme color.
     */
    public function getPrimaryColorAttribute(): string
    {
        return $this->theme_colors['primary'] ?? '#10b981';
    }

    /**
     * Get the secondary theme color.
     */
    public function getSecondaryColorAttribute(): string
    {
        return $this->theme_colors['secondary'] ?? '#3b82f6';
    }

    // =========================================================================
    // HELPER METHODS
    // =========================================================================

    /**
     * Get the first text block content.
     */
    protected function getFirstTextBlock(): string
    {
        if (empty($this->content_blocks)) {
            return '';
        }

        foreach ($this->content_blocks as $block) {
            $block = $this->normalizeBlock($block);

            if (in_array($block['type'] ?? 'text', ['text', 'paragraph', 'quote', 'heading'], true)) {
                return $block['content'] ?? $block['title'] ?? '';
            }
        }

        return '';
    }

    /**
     * Normalize block content for rendering and compatibility.
     */
    protected function normalizeBlock(array $block): array
    {
        if (!empty($block['heading']) && empty($block['title'])) {
            $block['title'] = $block['heading'];
        }

        if (!empty($block['body']) && empty($block['content'])) {
            $block['content'] = $block['body'];
        }

        if (!empty($block['question']) && empty($block['title'])) {
            $block['title'] = $block['question'];
        }

        if (!empty($block['answer']) && empty($block['content'])) {
            $block['content'] = $block['answer'];
        }

        if (!empty($block['description']) && empty($block['subtitle'])) {
            $block['subtitle'] = $block['description'];
        }

        if ($block['type'] === 'cta') {
            if (empty($block['buttons'])) {
                $buttons = [];

                if (!empty($block['button_text']) || !empty($block['button_url'])) {
                    $buttons[] = [
                        'label' => $block['button_text'] ?? 'Learn More',
                        'url' => $block['button_url'] ?? '#',
                        'style' => $block['button_style'] ?? 'primary',
                        'icon' => $block['button_icon'] ?? ($block['icon'] ?? null),
                    ];
                } elseif (!empty($block['label'])) {
                    $buttons[] = [
                        'label' => $block['label'],
                        'url' => $block['url'] ?? $block['value'] ?? '#',
                        'style' => $block['button_style'] ?? 'primary',
                        'icon' => $block['icon'] ?? null,
                    ];
                }

                if (!empty($buttons)) {
                    $block['buttons'] = $buttons;
                }
            }
        }

        if (!empty($block['items']) && is_array($block['items'])) {
            foreach ($block['items'] as $itemIndex => $item) {
                if (!empty($item['question']) && empty($item['title'])) {
                    $block['items'][$itemIndex]['title'] = $item['question'];
                }
                if (!empty($item['answer']) && empty($block['items'][$itemIndex]['content'])) {
                    $block['items'][$itemIndex]['content'] = $item['answer'];
                }
            }
        }

        if (!empty($block['tabs']) && is_array($block['tabs'])) {
            foreach ($block['tabs'] as $tabIndex => $tab) {
                if (!empty($tab['question']) && empty($block['tabs'][$tabIndex]['label'])) {
                    $block['tabs'][$tabIndex]['label'] = $tab['question'];
                }
                if (!empty($tab['answer']) && empty($block['tabs'][$tabIndex]['content'])) {
                    $block['tabs'][$tabIndex]['content'] = $tab['answer'];
                }
            }
        }

        if (!empty($block['cards']) && is_array($block['cards'])) {
            foreach ($block['cards'] as $cardIndex => $card) {
                if (!empty($card['heading']) && empty($block['cards'][$cardIndex]['title'])) {
                    $block['cards'][$cardIndex]['title'] = $card['heading'];
                }
                if (!empty($card['body']) && empty($block['cards'][$cardIndex]['description'])) {
                    $block['cards'][$cardIndex]['description'] = $card['body'];
                }
            }
        }

        if (!empty($block['images']) && is_array($block['images'])) {
            foreach ($block['images'] as $imageIndex => $image) {
                if (!empty($image['image']) && empty($block['images'][$imageIndex]['path'])) {
                    $block['images'][$imageIndex]['path'] = $image['image'];
                }
                if (!empty($image['image_alt']) && empty($block['images'][$imageIndex]['alt'])) {
                    $block['images'][$imageIndex]['alt'] = $image['image_alt'];
                }
            }
        }

        if (!empty($block['content']) && !Str::contains($block['content'], ['<p', '<br', '<ul', '<ol', '<strong', '<em', '<a', '<div', '<span', '<h', '<img'])) {
            $block['content'] = nl2br(e($block['content']));
        }

        if (!empty($block['subtitle']) && !Str::contains($block['subtitle'], ['<p', '<br', '<ul', '<ol', '<strong', '<em', '<a', '<div', '<span', '<h', '<img'])) {
            $block['subtitle'] = nl2br(e($block['subtitle']));
        }

        if (!empty($block['items']) && is_array($block['items'])) {
            foreach ($block['items'] as $itemIndex => $item) {
                if (!empty($block['items'][$itemIndex]['content']) && !Str::contains($block['items'][$itemIndex]['content'], ['<p', '<br', '<ul', '<ol', '<strong', '<em', '<a', '<div', '<span', '<h', '<img'])) {
                    $block['items'][$itemIndex]['content'] = nl2br(e($block['items'][$itemIndex]['content']));
                }
            }
        }

        if (!empty($block['tabs']) && is_array($block['tabs'])) {
            foreach ($block['tabs'] as $tabIndex => $tab) {
                if (!empty($block['tabs'][$tabIndex]['content']) && !Str::contains($block['tabs'][$tabIndex]['content'], ['<p', '<br', '<ul', '<ol', '<strong', '<em', '<a', '<div', '<span', '<h', '<img'])) {
                    $block['tabs'][$tabIndex]['content'] = nl2br(e($block['tabs'][$tabIndex]['content']));
                }
            }
        }

        if (!empty($block['cards']) && is_array($block['cards'])) {
            foreach ($block['cards'] as $cardIndex => $card) {
                if (!empty($block['cards'][$cardIndex]['description']) && !Str::contains($block['cards'][$cardIndex]['description'], ['<p', '<br', '<ul', '<ol', '<strong', '<em', '<a', '<div', '<span', '<h', '<img'])) {
                    $block['cards'][$cardIndex]['description'] = nl2br(e($block['cards'][$cardIndex]['description']));
                }
            }
        }

        return $block;
    }

    /**
     * Render all content blocks.
     */
    public function renderBlocks(): string
    {
        if (empty($this->content_blocks)) {
            return '';
        }

        $html = '';
        foreach ($this->content_blocks as $index => $block) {
            $html .= $this->renderBlock($this->normalizeBlock($block), $index);
        }

        return $html;
    }

    /**
     * Render a single content block.
     */
    public function renderBlock(array $block, int $index = 0): string
    {
        $type = $block['type'] ?? 'text';
        $viewName = "publishing.blocks.{$type}";

        if (view()->exists($viewName)) {
            return view($viewName, [
                'block' => $block,
                'index' => $index,
                'page' => $this,
            ])->render();
        }

        return '<section class="py-12"><div class="max-w-7xl mx-auto px-4"><div class="bg-yellow-50 border border-yellow-300 text-yellow-900 rounded-lg p-6">Unsupported publishing block type: <strong>' . htmlspecialchars($type, ENT_QUOTES, 'UTF-8') . '</strong></div></div></section>';
    }

    /**
     * Check if the page is publicly viewable.
     */
    public function isPubliclyViewable(): bool
    {
        return $this->is_published;
    }

    /**
     * Generate a unique slug.
     */
    public static function generateUniqueSlug(string $title): string
    {
        $slug = Str::slug($title);
        $count = static::where('slug', 'like', "{$slug}%")->count();

        return $count > 0 ? "{$slug}-{$count}" : $slug;
    }

    /**
     * Publish the page.
     */
    public function publish(): void
    {
        $this->update([
            'is_published' => true,
            'published_at' => now(),
        ]);
    }

    /**
     * Unpublish the page.
     */
    public function unpublish(): void
    {
        $this->update([
            'is_published' => false,
        ]);
    }

    /**
     * Increment view count.
     */
    public function incrementViewCount(): void
    {
        $this->increment('view_count');
    }

    /**
     * Add a content block.
     */
    public function addBlock(array $block): void
    {
        $blocks = $this->content_blocks ?? [];
        $blocks[] = $block;
        $this->update(['content_blocks' => $blocks]);
    }

    /**
     * Update a content block.
     */
    public function updateBlock(int $index, array $block): void
    {
        $blocks = $this->content_blocks ?? [];
        if (isset($blocks[$index])) {
            $blocks[$index] = $block;
            $this->update(['content_blocks' => $blocks]);
        }
    }

    /**
     * Remove a content block.
     */
    public function removeBlock(int $index): void
    {
        $blocks = $this->content_blocks ?? [];
        if (isset($blocks[$index])) {
            array_splice($blocks, $index, 1);
            $this->update(['content_blocks' => $blocks]);
        }
    }

    /**
     * Reorder content blocks.
     */
    public function reorderBlocks(array $order): void
    {
        $blocks = $this->content_blocks ?? [];
        $reordered = [];

        foreach ($order as $index) {
            if (isset($blocks[$index])) {
                $reordered[] = $blocks[$index];
            }
        }

        $this->update(['content_blocks' => $reordered]);
    }

    // =========================================================================
    // STATIC METHODS
    // =========================================================================

    /**
     * Get available block types.
     */
    public static function getBlockTypes(): array
    {
        return [
            'hero' => 'Hero Section',
            'text' => 'Text/Paragraph',
            'heading' => 'Heading',
            'image' => 'Single Image',
            'image_grid' => 'Image Grid',
            'carousel' => 'Carousel/Slider',
            'video' => 'Video Embed',
            'cta' => 'Call to Action',
            'split_screen' => 'Split Screen',
            'card_section' => 'Card Section',
            'quote' => 'Quote',
            'accordion' => 'Accordion/FAQ',
            'tabs' => 'Tab Section',
            'divider' => 'Divider',
            'spacer' => 'Spacer',
        ];
    }

    /**
     * Get available layouts.
     */
    public static function getLayouts(): array
    {
        return [
            'default' => 'Default (Full Width)',
            'boxed' => 'Boxed (Centered)',
            'sidebar-left' => 'Left Sidebar',
            'sidebar-right' => 'Right Sidebar',
        ];
    }
}
