<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
namespace app\service\domain\channel;

use app\repository\system\ConfigRepository;
use app\service\StorageService;
use Core\service\BaseCoreService;
use think\Request;

/**
 * 底部导航服务
 * @property ConfigRepository $configRepository
 * Class CoreBottomNavService
 * @package app\service\domain\channel
 */
class CoreBottomNavService extends BaseCoreService
{
    private const CONFIG_KEY = 'platform_bottom_nav_center';

    /**
     * 获取底部导航配置
     * @return array
     */
    public function adminConfig(): array
    {
        $config = $this->loadConfig();

        return [
            'links' => $config['links'],
            'menus' => $config['menus'],
            'link_types' => $this->linkTypeOptions(),
        ];
    }

    /**
     * 保存底部导航配置
     * @param array $payload
     * @return array
     */
    public function saveConfig(array $payload): array
    {
        $config = $this->normalizeConfig($payload);
        $this->configRepository()->setJson(self::CONFIG_KEY, $config, 'Channel bottom nav');

        return ['code' => 0, 'msg' => ''];
    }

    /**
     * 获取公共菜单
     * @param Request $request
     * @param string $channel
     * @param int $menuId
     * @return array
     */
    public function publicMenus(Request $request, string $channel = '', int $menuId = 0): array
    {
        $config = $this->loadConfig();
        $links = $this->linkMap($config['links']);
        $menus = [];

        foreach ($config['menus'] as $menu) {
            if ((int)($menu['status'] ?? 0) !== 1) {
                continue;
            }

            if (!$this->matchChannels($channel, is_array($menu['channels'] ?? null) ? $menu['channels'] : [])) {
                continue;
            }

            if ($menuId > 0 && (int)($menu['id'] ?? 0) !== $menuId) {
                continue;
            }

            $menus[] = $this->resolvePublicMenu($request, $menu, $links);
        }

        return array_values($menus);
    }

    /**
     * 规范底部导航配置
     * @param array $payload
     * @return array
     */
    private function normalizeConfig(array $payload): array
    {
        $catalogChannels = array_keys($this->catalog()->channels());
        $links = $this->normalizeLinks(is_array($payload['links'] ?? null) ? $payload['links'] : []);
        $linkIds = array_map(static fn (array $item): int => (int)($item['id'] ?? 0), $links);

        return [
            'links' => $links,
            'menus' => $this->normalizeMenus(
                is_array($payload['menus'] ?? null) ? $payload['menus'] : [],
                $catalogChannels,
                $linkIds
            ),
        ];
    }

    /**
     * 规范底部导航链接
     * @param array $links
     * @return array
     */
    private function normalizeLinks(array $links): array
    {
        $rows = [];
        $maxId = 0;

        foreach ($links as $index => $link) {
            if (!is_array($link)) {
                continue;
            }

            $id = max((int)($link['id'] ?? 0), $maxId + 1);
            $maxId = max($maxId, $id);
            $type = trim((string)($link['type'] ?? 'internal'));
            if (!array_key_exists($type, $this->linkTypeOptions())) {
                $type = 'internal';
            }

            $rows[] = [
                'id' => $id,
                'name' => mb_substr(trim((string)($link['name'] ?? ('' . ($index + 1)))), 0, 50),
                'type' => $type,
                'path' => trim((string)($link['path'] ?? '')),
                'open_type' => trim((string)($link['open_type'] ?? 'navigateTo')) === 'switchTab' ? 'switchTab' : 'navigateTo',
                'app_id' => trim((string)($link['app_id'] ?? '')),
                'page_path' => trim((string)($link['page_path'] ?? '')),
                'url' => trim((string)($link['url'] ?? '')),
            ];
        }

        return array_values($rows);
    }

    /**
     * 规范底部导航菜单
     * @param array $menus
     * @param array $catalogChannels
     * @param array $linkIds
     * @return array
     */
    private function normalizeMenus(array $menus, array $catalogChannels, array $linkIds): array
    {
        $rows = [];
        $maxId = 0;

        foreach ($menus as $index => $menu) {
            if (!is_array($menu)) {
                continue;
            }

            $id = max((int)($menu['id'] ?? 0), $maxId + 1);
            $maxId = max($maxId, $id);
            $style = is_array($menu['style'] ?? null) ? $menu['style'] : [];
            $items = is_array($menu['items'] ?? null) ? $menu['items'] : [];
            $channels = array_values(array_unique(array_filter(array_map(
                static fn ($item): string => trim((string)$item),
                is_array($menu['channels'] ?? null) ? $menu['channels'] : []
            ), static fn (string $channel): bool => in_array($channel, $catalogChannels, true))));

            $rows[] = [
                'id' => $id,
                'name' => mb_substr(trim((string)($menu['name'] ?? ('' . ($index + 1)))), 0, 50),
                'status' => (int)($menu['status'] ?? 1) === 1 ? 1 : 0,
                'channels' => $channels,
                'style' => [
                    'display_type' => $this->normalizeDisplayType((string)($style['display_type'] ?? 'icon_text')),
                    'text_color' => $this->normalizeColor($style['text_color'] ?? '#999999', '#999999'),
                    'active_text_color' => $this->normalizeColor($style['active_text_color'] ?? '#1ec7a3', '#1ec7a3'),
                ],
                'items' => $this->normalizeMenuItems($items, $linkIds),
            ];
        }

        return array_values($rows);
    }

    /**
     * 规范底部导航菜单项
     * @param array $items
     * @param array $linkIds
     * @return array
     */
    private function normalizeMenuItems(array $items, array $linkIds): array
    {
        $rows = [];

        foreach ($items as $index => $item) {
            if (!is_array($item)) {
                continue;
            }

            $linkId = (int)($item['link_id'] ?? 0);
            if (!in_array($linkId, $linkIds, true)) {
                $linkId = 0;
            }

            $rows[] = [
                'label' => mb_substr(trim((string)($item['label'] ?? ('' . ($index + 1)))), 0, 10),
                'link_id' => $linkId,
                'default_icon' => StorageService::normalizeAttachmentValue((string)($item['default_icon'] ?? '')),
                'active_icon' => StorageService::normalizeAttachmentValue((string)($item['active_icon'] ?? '')),
            ];
        }

        return array_values($rows);
    }

    /**
     * 规范底部导航链接映射
     * @param array $links
     * @return array
     */
    private function linkMap(array $links): array
    {
        $map = [];
        foreach ($links as $link) {
            $id = (int)($link['id'] ?? 0);
            if ($id <= 0) {
                continue;
            }

            $map[$id] = [
                'id' => $id,
                'name' => (string)($link['name'] ?? ''),
                'type' => (string)($link['type'] ?? 'internal'),
                'path' => (string)($link['path'] ?? ''),
                'open_type' => (string)($link['open_type'] ?? 'navigateTo'),
                'app_id' => (string)($link['app_id'] ?? ''),
                'page_path' => (string)($link['page_path'] ?? ''),
                'url' => (string)($link['url'] ?? ''),
            ];
        }

        return $map;
    }

    /**
     * 获取公共菜单
     * @param Request $request
     * @param array $menu
     * @param array $links
     * @return array
     */
    private function resolvePublicMenu(Request $request, array $menu, array $links): array
    {
        $items = [];
        foreach ((array)($menu['items'] ?? []) as $item) {
            $linkId = (int)($item['link_id'] ?? 0);
            if ($linkId <= 0 || !isset($links[$linkId])) {
                continue;
            }

            $items[] = [
                'label' => (string)($item['label'] ?? ''),
                'default_icon' => StorageService::toFullAssetUrl($request, (string)($item['default_icon'] ?? '')),
                'active_icon' => StorageService::toFullAssetUrl($request, (string)($item['active_icon'] ?? '')),
                'link' => $links[$linkId],
            ];
        }

        return [
            'id' => (int)($menu['id'] ?? 0),
            'name' => (string)($menu['name'] ?? ''),
            'channels' => array_values((array)($menu['channels'] ?? [])),
            'style' => is_array($menu['style'] ?? null) ? $menu['style'] : [],
            'items' => $items,
        ];
    }

    /**
     * 匹配渠道
     * @param string $channel
     * @param array $channels
     * @return bool
     */
    private function matchChannels(string $channel, array $channels): bool
    {
        $current = trim($channel);
        if (empty($channels)) {
            return true;
        }

        if ($current === '') {
            return false;
        }

        return in_array($current, $channels, true);
    }

    /**
     * 加载底部导航配置
     * @return array
     */
    private function loadConfig(): array
    {
        $raw = $this->configRepository()->getJson(self::CONFIG_KEY, []);
        $config = $this->normalizeConfig(is_array($raw) ? $raw : []);

        return [
            'links' => $config['links'],
            'menus' => $config['menus'],
        ];
    }

    /**
     * 获取底部导航链接类型选项
     * @return array
     */
    private function linkTypeOptions(): array
    {
        return [
            'internal' => '内部页面',
            'mini_program' => '跳转小程序',
            'external' => '外部链接',
        ];
    }

    /**
     * 规范底部导航颜色
     * @param mixed $value
     * @param string $default
     * @return string
     */
    private function normalizeColor($value, string $default): string
    {
        $color = trim((string)$value);
        if (preg_match('/^#[0-9a-fA-F]{6}$/', $color)) {
            return strtolower($color);
        }

        return $default;
    }

    /**
     * 规范底部导航显示类型
     * @param string $value
     * @return string
     */
    private function normalizeDisplayType(string $value): string
    {
        return match ($value) {
            'icon', 'text' => $value,
            default => 'icon_text',
        };
    }

    /**
     * 获取底部导航配置仓库
     * @return ConfigRepository
     */
    private function configRepository(): ConfigRepository
    {
        return $this->app->make(ConfigRepository::class);
    }

    /**
     * 获取底部导航目录服务
     * @return CoreChannelCatalogService
     */
    private function catalog(): CoreChannelCatalogService
    {
        return $this->app->make(CoreChannelCatalogService::class);
    }
}
