<?php

namespace App\Domain\Website\Services;

use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Website\Models\WebsiteBlock;
use App\Domain\Website\Models\WebsitePage;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class WebsitePageService
{
    /** Slugs that would collide with real application routes. */
    public const RESERVED_SLUGS = [
        'admin', 'login', 'logout', 'register', 'password', 'api', 'public', 'app',
        'website', 'parent', 'trainer', 'receptionist', 'dashboard', 'storage',
        'livewire', 'up', 'health',
        // Locale prefixes address the whole site in a language; a page slug that
        // collided with one would be unreachable behind its own prefix.
        'en', 'ar',
    ];

    public function create(array $data, User $actor): WebsitePage
    {
        return DB::transaction(function () use ($data, $actor) {
            $slug = $this->uniqueSlug($data['slug'] ?? $data['title'] ?? 'page');

            $page = WebsitePage::create([
                'slug' => $slug,
                'title' => $data['title'] ?? null,
                'title_en' => $data['title_en'] ?? null,
                'meta_title' => $data['meta_title'] ?? null,
                'meta_title_en' => $data['meta_title_en'] ?? null,
                'meta_description' => $data['meta_description'] ?? null,
                'meta_description_en' => $data['meta_description_en'] ?? null,
                'layout' => $data['layout'] ?? 'default',
                'is_homepage' => false,
                'is_published' => $data['is_published'] ?? false,
                'published_at' => ($data['is_published'] ?? false) ? now() : null,
                'sort_order' => $data['sort_order'] ?? ((WebsitePage::max('sort_order') ?? 0) + 1),
                'settings' => $data['settings'] ?? [],
                'created_by' => $actor->id,
            ]);

            if ($data['is_homepage'] ?? false) {
                $this->makeHomepage($page);
            }

            return $page;
        });
    }

    public function update(WebsitePage $page, array $data): WebsitePage
    {
        return DB::transaction(function () use ($page, $data) {
            if (array_key_exists('slug', $data) && $data['slug'] !== $page->slug) {
                $data['slug'] = $this->uniqueSlug($data['slug'], $page->id);
            }

            if (array_key_exists('is_published', $data)) {
                $data['published_at'] = $data['is_published']
                    ? ($page->published_at ?? now())
                    : null;
            }

            $wantsHomepage = (bool) ($data['is_homepage'] ?? false);
            unset($data['is_homepage']);

            $page->update($data);

            if ($wantsHomepage && ! $page->is_homepage) {
                $this->makeHomepage($page);
            }

            return $page->refresh();
        });
    }

    /**
     * Promotes a page to homepage. Demoting the previous one first is required —
     * a partial unique index enforces exactly one homepage per academy.
     */
    public function makeHomepage(WebsitePage $page): WebsitePage
    {
        return DB::transaction(function () use ($page) {
            WebsitePage::where('is_homepage', true)
                ->where('id', '!=', $page->id)
                ->update(['is_homepage' => false]);

            $page->update(['is_homepage' => true, 'is_published' => true]);

            return $page->refresh();
        });
    }

    /** Deep-copies a page and its entire block tree. */
    public function duplicate(WebsitePage $page, User $actor): WebsitePage
    {
        return DB::transaction(function () use ($page, $actor) {
            $copy = $page->replicate(['uuid', 'is_homepage', 'is_published', 'published_at']);
            $copy->uuid = (string) Str::uuid();
            $copy->slug = $this->uniqueSlug($page->slug.'-copy');
            $copy->title = $page->title ? $page->title.' (نسخة)' : null;
            $copy->title_en = $page->title_en ? $page->title_en.' (copy)' : null;
            $copy->is_homepage = false;
            $copy->is_published = false;
            $copy->published_at = null;
            $copy->created_by = $actor->id;
            $copy->save();

            foreach ($page->blocks as $block) {
                app(WebsiteBlockService::class)->copyTree($block, $copy->id, null);
            }

            return $copy;
        });
    }

    public function delete(WebsitePage $page): void
    {
        if ($page->is_homepage) {
            throw new DomainException('لا يمكن حذف الصفحة الرئيسية. عيّن صفحة أخرى كرئيسية أولًا.');
        }

        DB::transaction(function () use ($page) {
            WebsiteBlock::where('website_page_id', $page->id)->delete();
            $page->delete();
        });
    }

    public function reorder(array $orderedIds): void
    {
        DB::transaction(function () use ($orderedIds) {
            foreach ($orderedIds as $i => $id) {
                WebsitePage::where('id', $id)->update(['sort_order' => $i]);
            }
        });
    }

    /**
     * Produces a slug that is URL-safe, unique for the academy, and not a
     * reserved application route. Arabic titles slugify to empty, so a
     * deterministic fallback is required rather than an empty slug.
     */
    public function uniqueSlug(string $source, ?int $ignoreId = null): string
    {
        $base = Str::slug($source);

        if ($base === '') {
            $base = Str::slug(Str::ascii($source)) ?: 'page-'.Str::lower(Str::random(6));
        }

        if (in_array($base, self::RESERVED_SLUGS, true)) {
            $base .= '-page';
        }

        $slug = $base;
        $n = 2;

        while (WebsitePage::withTrashed()
            ->where('slug', $slug)
            ->when($ignoreId, fn ($q) => $q->where('id', '!=', $ignoreId))
            ->exists()) {
            $slug = "{$base}-{$n}";
            $n++;
        }

        return $slug;
    }
}
