<?php defined('BASEPATH') or exit('No direct script access allowed');

class Client_Controller extends MY_Controller
{
	private const CLIENT_PERMISSION_CACHE_VERSION = 'v2';

	public function __construct()
	{
		
		$this->requireAuth = true;
		$this->allowedRoles = array(2); // Client only
		parent::__construct();

		$userId = (int) ($this->session->userdata('user_id') ?? 0);
		$userFlag = $this->session->userdata('user_flag');
		if (empty($userFlag)) {
			redirect('locked');
		}
		if ($userFlag != 2) {
			$url = $this->session->userdata('url');
			redirect($url ?: 'login');
		}
		
		
		$menuTree = isset($this->menu_tree) && is_array($this->menu_tree) ? $this->menu_tree : (isset($menu_tree) && is_array($menu_tree) ? $menu_tree : array());
		if (empty($menuTree)) {
			$this->load->model('Menu_model');
			$menuTree = $this->Menu_model->get_active_tree(false, true);
			$this->load->vars(array('menu_tree' => $menuTree));
		}

		// Build restricted links per client (cached per user).
		$cacheKey = 'client_exception_uris_' . self::CLIENT_PERMISSION_CACHE_VERSION . '_' . $userId;
		$exception_uris = $this->cache->get($cacheKey);
		if ($exception_uris === FALSE) {
			$exception_uris = $this->buildClientRestrictedUris($menuTree);
			$this->cache->save($cacheKey, $exception_uris, 300);
		}

		// Allow certain profile routes.
		$except_uri = array(
			'client/settings/update_profile',
			'client/settings/profile_updated',
			'client/settings/set_password',
			'client/settings/change_email',
			'client/settings/change_username',
			'client/settings/activities',
			'client/announcements/view_announcements_details',
			'client/announcements/announcements_details',
			'client/announcements/download_files'
		);

		$currentUri = trim(uri_string(), '/');
		$isExceptUri = false;
		foreach ($except_uri as $allowedUri) {
			$allowedUri = trim((string) $allowedUri, '/');
			if ($allowedUri !== '' && ($currentUri === $allowedUri || strpos($currentUri, $allowedUri . '/') === 0)) {
				$isExceptUri = true;
				break;
			}
		}
		if (!$isExceptUri) {
			foreach ((array) $exception_uris as $restrictedUri) {
				$restrictedUri = trim((string) $restrictedUri, '/');
				if ($restrictedUri === '') {
					continue;
				}
				if ($currentUri === $restrictedUri || strpos($currentUri, $restrictedUri . '/') === 0) {
					redirect('404');
				}
			}
		}
	}

	private function buildClientRestrictedUris(array $menuTree): array
	{
		$allowedLinks = array();
		$this->collectTreeRoutes($menuTree, $allowedLinks);

		// Always allow dashboard root.
		$allowedLinks['client/dashboard'] = true;

		$allMenuLinks = array();
		$allMenus = $this->db->select('link')->get('tbl_client_menu')->result();
		if (!empty($allMenus)) {
			foreach ($allMenus as $menuItem) {
				$link = trim((string) ($menuItem->link ?? ''), '/');
				if ($link !== '') {
					$allMenuLinks[$link] = true;
				}
			}
		}

		$restricted = array_values(array_diff(array_keys($allMenuLinks), array_keys($allowedLinks)));
		return array_values(array_diff($restricted, array('client/dashboard')));
	}

	private function collectTreeRoutes(array $items, array &$collector): void
	{
		if (empty($items)) {
			return;
		}
		foreach ($items as $item) {
			$route = trim((string) ($item['route'] ?? ''), '/');
			if ($route !== '') {
				$collector[$route] = true;
			}
			if (!empty($item['children']) && is_array($item['children'])) {
				$this->collectTreeRoutes($item['children'], $collector);
			}
		}
	}
}
