<?php

declare(strict_types=1);

namespace ApiModel\Service;

use ApiModel\Domain\Repository\ModuleRepositoryInterface;
use ApiModel\Domain\Repository\PageRepositoryInterface;
use ApiModel\Domain\Repository\ProfileRepositoryInterface;
use ApiModel\Domain\Repository\SecurityMenuRepositoryInterface;
use ApiModel\Infrastructure\Persistence\Database;
use ApiModel\Shared\Exceptions\NotFoundException;

final class MenuService
{
    public function __construct(
        private readonly ModuleRepositoryInterface $modules,
        private readonly PageRepositoryInterface $pages,
        private readonly ProfileRepositoryInterface $profiles,
        private readonly ?SecurityMenuRepositoryInterface $securityMenu = null
    ) {}

    /**
     * Retorna el árbol de menú dinámico para el usuario según sus permisos y el idioma especificado.
     *
     * @return array<string, mixed>|list<array<string, mixed>>
     */
    public function getMenuForUser(string $userId, string $lang): array
    {
        if ($this->securityMenu !== null) {
            return [
                'menu' => $this->securityMenu->getMenuForUser($userId),
                'pages' => $this->securityMenu->getPagesForUser($userId),
            ];
        }

        $lang = strtolower(trim($lang)) === 'en' ? 'en' : 'es';

        if ($this->profiles->userIsAdministrator($userId)) {
            return $this->buildFullMenu($lang);
        }

        $userPerms = $this->profiles->getPermissionsForUser($userId);

        $menuMap = [];
        foreach ($userPerms as $perm) {
            // Solo incluimos páginas que el usuario pueda visualizar
            if (! $perm['can_view']) {
                continue;
            }

            $modId = $perm['module_id'];
            if (! isset($menuMap[$modId])) {
                $menuMap[$modId] = [
                    'id' => $modId,
                    'name' => $lang === 'en' ? $perm['module_name_en'] : $perm['module_name_es'],
                    'icon' => $perm['module_icon'],
                    'order' => $perm['module_order'],
                    'pages' => [],
                ];
            }

            $menuMap[$modId]['pages'][] = [
                'page_id' => $perm['page_id'],
                'name' => $lang === 'en' ? $perm['name_en'] : $perm['name_es'],
                'path' => $perm['path'],
                'icon' => $perm['page_icon'],
                'order' => $perm['page_order'],
                'permissions' => [
                    'can_view' => $perm['can_view'],
                    'can_create' => $perm['can_create'],
                    'can_edit' => $perm['can_edit'],
                    'can_delete' => $perm['can_delete'],
                ],
            ];
        }

        // Ordenamos los módulos según el order_index
        $menuList = array_values($menuMap);
        usort($menuList, static fn (array $a, array $b): int => $a['order'] <=> $b['order']);

        return $menuList;
    }

    /** @return list<array<string, mixed>> */
    private function buildFullMenu(string $lang): array
    {
        $menuList = [];
        foreach ($this->modules->listActive() as $mod) {
            $pages = $this->pages->listActiveByModule((string) $mod['id']);
            if ($pages === []) {
                continue;
            }

            $entry = [
                'id' => $mod['id'],
                'name' => $lang === 'en' ? $mod['name_en'] : $mod['name_es'],
                'name_es' => $mod['name_es'],
                'name_en' => $mod['name_en'],
                'icon' => $mod['icon'],
                'order' => (int) $mod['order_index'],
                'order_index' => (int) $mod['order_index'],
                'pages' => [],
            ];

            foreach ($pages as $pg) {
                $entry['pages'][] = [
                    'page_id' => $pg['id'],
                    'id' => $pg['id'],
                    'name' => $lang === 'en' ? $pg['name_en'] : $pg['name_es'],
                    'name_es' => $pg['name_es'],
                    'name_en' => $pg['name_en'],
                    'path' => $pg['path'],
                    'icon' => $pg['icon'],
                    'order' => (int) $pg['order_index'],
                    'order_index' => (int) $pg['order_index'],
                    'permissions' => [
                        'can_view' => true,
                        'can_create' => true,
                        'can_edit' => true,
                        'can_delete' => true,
                    ],
                ];
            }

            $menuList[] = $entry;
        }

        usort($menuList, static fn (array $a, array $b): int => $a['order'] <=> $b['order']);

        return $menuList;
    }

    public function listModules(): array
    {
        return $this->modules->listAll();
    }

    public function createModule(string $nameEs, string $nameEn, ?string $icon, int $orderIndex): array
    {
        $id = Database::uuid();
        $this->modules->insert($id, $nameEs, $nameEn, $icon, $orderIndex);
        return $this->modules->findById($id) ?? [];
    }

    public function updateModule(string $id, string $nameEs, string $nameEn, ?string $icon, int $orderIndex, bool $isActive): array
    {
        $mod = $this->modules->findById($id);
        if (! $mod) {
            throw new NotFoundException('Módulo no encontrado');
        }
        $this->modules->update($id, $nameEs, $nameEn, $icon, $orderIndex, $isActive);
        return $this->modules->findById($id) ?? [];
    }

    public function listPages(): array
    {
        return $this->pages->listAll();
    }

    public function createPage(string $moduleId, string $nameEs, string $nameEn, string $path, ?string $icon, int $orderIndex): array
    {
        $id = Database::uuid();
        $this->pages->insert($id, $moduleId, $nameEs, $nameEn, $path, $icon, $orderIndex);
        return $this->pages->findById($id) ?? [];
    }

    public function updatePage(string $id, string $moduleId, string $nameEs, string $nameEn, string $path, ?string $icon, int $orderIndex, bool $isActive): array
    {
        $pg = $this->pages->findById($id);
        if (! $pg) {
            throw new NotFoundException('Página no encontrada');
        }
        $this->pages->update($id, $moduleId, $nameEs, $nameEn, $path, $icon, $orderIndex, $isActive);
        return $this->pages->findById($id) ?? [];
    }

    public function deleteModule(string $id): void
    {
        $mod = $this->modules->findById($id);
        if (! $mod) {
            throw new NotFoundException('Módulo no encontrado');
        }
        $this->modules->delete($id);
    }

    public function deletePage(string $id): void
    {
        $pg = $this->pages->findById($id);
        if (! $pg) {
            throw new NotFoundException('Página no encontrada');
        }
        $this->pages->delete($id);
    }
}
