<?php

namespace App\Services;

use App\Models\Commons\Menu;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

/**
 * 글로벌 메뉴 관리 서비스 (시스템 관리자용)
 */
class GlobalMenuService extends Service
{
    /**
     * 글로벌 메뉴 목록 조회
     */
    public function index(array $params = []): Collection
    {
        $query = Menu::global();

        // 필터: 활성 상태
        if (isset($params['is_active'])) {
            $query->where('is_active', (bool) $params['is_active']);
        }

        // 필터: 숨김 상태
        if (isset($params['hidden'])) {
            $query->where('hidden', (bool) $params['hidden']);
        }

        // 필터: 상위 메뉴
        if (array_key_exists('parent_id', $params)) {
            $query->where('parent_id', $params['parent_id']);
        }

        return $query
            ->orderByRaw('COALESCE(parent_id, 0)')
            ->orderBy('sort_order')
            ->get();
    }

    /**
     * 글로벌 메뉴 트리 구조로 조회
     */
    public function tree(): Collection
    {
        $menus = Menu::global()
            ->orderBy('sort_order')
            ->get();

        return $this->buildTree($menus);
    }

    /**
     * 글로벌 메뉴 단건 조회
     */
    public function show(int $id): ?Menu
    {
        return Menu::global()
            ->with('children')
            ->find($id);
    }

    /**
     * 글로벌 메뉴 생성
     */
    public function store(array $data): Menu
    {
        return Menu::create([
            'tenant_id' => null, // 글로벌 메뉴
            'parent_id' => $data['parent_id'] ?? null,
            'name' => $data['name'],
            'url' => $data['url'] ?? null,
            'icon' => $data['icon'] ?? null,
            'sort_order' => $data['sort_order'] ?? 0,
            'is_active' => $data['is_active'] ?? true,
            'hidden' => $data['hidden'] ?? false,
            'is_external' => $data['is_external'] ?? false,
            'external_url' => $data['external_url'] ?? null,
            'created_by' => $this->apiUserId(),
            'updated_by' => $this->apiUserId(),
        ]);
    }

    /**
     * 글로벌 메뉴 수정
     */
    public function update(int $id, array $data): ?Menu
    {
        $menu = Menu::global()->find($id);

        if (! $menu) {
            return null;
        }

        $updateData = array_filter([
            'parent_id' => $data['parent_id'] ?? null,
            'name' => $data['name'] ?? null,
            'url' => $data['url'] ?? null,
            'icon' => $data['icon'] ?? null,
            'sort_order' => $data['sort_order'] ?? null,
            'is_active' => isset($data['is_active']) ? (bool) $data['is_active'] : null,
            'hidden' => isset($data['hidden']) ? (bool) $data['hidden'] : null,
            'is_external' => isset($data['is_external']) ? (bool) $data['is_external'] : null,
            'external_url' => $data['external_url'] ?? null,
        ], fn ($v) => ! is_null($v));

        $updateData['updated_by'] = $this->apiUserId();

        $menu->update($updateData);

        return $menu->fresh();
    }

    /**
     * 글로벌 메뉴 삭제
     * - 연결된 테넌트 메뉴의 global_menu_id를 NULL로 변경
     */
    public function destroy(int $id): bool
    {
        $menu = Menu::global()->find($id);

        if (! $menu) {
            return false;
        }

        return DB::transaction(function () use ($menu) {
            // 연결된 테넌트 메뉴의 global_menu_id를 NULL로 변경
            Menu::withoutGlobalScopes()
                ->where('global_menu_id', $menu->id)
                ->update(['global_menu_id' => null]);

            // 하위 메뉴도 삭제
            Menu::global()
                ->where('parent_id', $menu->id)
                ->delete();

            $menu->deleted_by = $this->apiUserId();
            $menu->save();
            $menu->delete();

            return true;
        });
    }

    /**
     * 글로벌 메뉴 순서 변경
     */
    public function reorder(array $items): bool
    {
        return DB::transaction(function () use ($items) {
            foreach ($items as $item) {
                if (! isset($item['id'], $item['sort_order'])) {
                    continue;
                }

                Menu::global()
                    ->where('id', $item['id'])
                    ->update([
                        'sort_order' => (int) $item['sort_order'],
                        'updated_by' => $this->apiUserId(),
                    ]);
            }

            return true;
        });
    }

    /**
     * 특정 글로벌 메뉴를 모든 테넌트에 동기화
     * - 이미 복제된 테넌트는 건너뜀
     */
    public function syncToAllTenants(int $globalMenuId): array
    {
        $globalMenu = Menu::global()->find($globalMenuId);

        if (! $globalMenu) {
            return ['synced' => 0, 'skipped' => 0, 'details' => []];
        }

        // 모든 테넌트 ID 조회
        $tenantIds = Menu::withoutGlobalScopes()
            ->whereNotNull('tenant_id')
            ->distinct()
            ->pluck('tenant_id');

        $synced = 0;
        $skipped = 0;
        $details = [];

        foreach ($tenantIds as $tenantId) {
            // 이미 복제된 경우 건너뜀
            $exists = Menu::withoutGlobalScopes()
                ->where('tenant_id', $tenantId)
                ->where('global_menu_id', $globalMenuId)
                ->exists();

            if ($exists) {
                $skipped++;
                $details[] = [
                    'tenant_id' => $tenantId,
                    'action' => 'skipped',
                    'reason' => 'already_exists',
                ];

                continue;
            }

            // 복제
            $newMenu = MenuBootstrapService::cloneSingleMenu($globalMenuId, $tenantId);

            if ($newMenu) {
                $synced++;
                $details[] = [
                    'tenant_id' => $tenantId,
                    'action' => 'created',
                    'tenant_menu_id' => $newMenu->id,
                ];
            }
        }

        return [
            'synced' => $synced,
            'skipped' => $skipped,
            'details' => $details,
        ];
    }

    /**
     * 글로벌 메뉴 통계 조회
     */
    public function stats(): array
    {
        $total = Menu::global()->count();
        $active = Menu::global()->where('is_active', true)->count();
        $inactive = Menu::global()->where('is_active', false)->count();
        $hidden = Menu::global()->where('hidden', true)->count();

        // 테넌트별 사용 현황
        $tenantUsage = Menu::withoutGlobalScopes()
            ->whereNotNull('global_menu_id')
            ->groupBy('global_menu_id')
            ->selectRaw('global_menu_id, COUNT(DISTINCT tenant_id) as tenant_count')
            ->pluck('tenant_count', 'global_menu_id')
            ->toArray();

        return [
            'total' => $total,
            'active' => $active,
            'inactive' => $inactive,
            'hidden' => $hidden,
            'tenant_usage' => $tenantUsage,
        ];
    }

    /**
     * 메뉴 컬렉션을 트리 구조로 변환
     */
    private function buildTree(Collection $menus, ?int $parentId = null): Collection
    {
        return $menus
            ->filter(fn ($menu) => $menu->parent_id === $parentId)
            ->map(function ($menu) use ($menus) {
                $menu->children = $this->buildTree($menus, $menu->id);

                return $menu;
            })
            ->values();
    }
}
