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

/**
 * Permission Helper
 * 
 * Core functions for role-based access control in multi-company system.
 * 
 * @version 1.0
 * @date 2026-01-15
 */

/**
 * Check if current user has a specific permission
 * 
 * @param string $permission_key The permission to check (e.g., 'company.create')
 * @return bool True if user has permission, false otherwise
 */
if (!function_exists('can')) {
    function can($permission_key) {
        $CI =& get_instance();
        
        // Get current user's role
        $role_id = $CI->session->userdata('role_id');
        
        if (empty($role_id)) {
            return false;
        }
        
        // Super Admin (role_id = 1) has all permissions
        if ($role_id == '1') {
            return true;
        }
        
        // Check permission from database
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        return $CI->Permission_model->has_permission($role_id, $permission_key);
    }
}

/**
 * Check if current user has access to a specific company
 * 
 * @param int $company_id The company ID to check
 * @return bool True if user has access, false otherwise
 */
if (!function_exists('has_company_access')) {
    function has_company_access($company_id) {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id'); // Fixed: was 'user_id', should be 'id'
        
        if (empty($role_id) || empty($user_id)) {
            return false;
        }
        
        // Super Admin has access to all companies
        if ($role_id == '1') {
            return true;
        }
        
        // Admin and User - check if assigned to this company
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        // First check new user_companies table
        if ($CI->Permission_model->user_has_company_access($user_id, $company_id)) {
            return true;
        }
        
        // Fallback: Check old users.user_company CSV field for backward compatibility
        $user = $CI->db->select('user_company')
            ->where('id', $user_id)
            ->get('users')
            ->row();
        
        if ($user && !empty($user->user_company)) {
            $company_ids = array_map('trim', explode(',', $user->user_company));
            return in_array($company_id, $company_ids);
        }
        
        return false;
    }
}

/**
 * Get list of company IDs the current user can access
 * 
 * @return array Array of company IDs
 */
if (!function_exists('get_allowed_companies')) {
    function get_allowed_companies() {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id'); // Fixed: was 'user_id', should be 'id'
        
        if (empty($role_id) || empty($user_id)) {
            return [];
        }
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        // Super Admin gets all companies
        if ($role_id == '1') {
            return $CI->Permission_model->get_all_company_ids();
        }
        
        // Admin and User get only their assigned companies
        // Try new user_companies table first
        $company_ids = $CI->Permission_model->get_user_company_ids($user_id);
        
        // Fallback: Check old users.user_company CSV field
        if (empty($company_ids)) {
            $user = $CI->db->select('user_company')
                ->where('id', $user_id)
                ->get('users')
                ->row();
            
            if ($user && !empty($user->user_company)) {
                $company_ids = array_map('trim', explode(',', $user->user_company));
            }
        }
        
        return $company_ids;
    }
}

/**
 * Get list of authority IDs the current user can access
 * 
 * @param int|null $company_id Optional company ID to filter by
 * @return array Array of authority IDs
 */
if (!function_exists('get_allowed_authorities')) {
    function get_allowed_authorities($company_id = null) {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id');
        
        if (empty($role_id) || empty($user_id)) {
            return [];
        }
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        // Super Admin and Admin get all authorities
        if ($role_id == '1' || $role_id == '2') {
            return $CI->Permission_model->get_all_authority_ids();
        }
        
        // User role gets only assigned authorities
        return $CI->Permission_model->get_user_authority_ids($user_id);
    }
}

/**
 * Get list of authority IDs the current user can access within a specific company
 * This is the new company-scoped version
 * 
 * @param int $company_id The company ID to filter by
 * @return array Array of authority IDs
 */
if (!function_exists('get_allowed_authorities_by_company')) {
    function get_allowed_authorities_by_company($company_id) {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id');
        
        if (empty($role_id) || empty($user_id) || empty($company_id)) {
            return [];
        }
        
        // Super Admin and Admin see all authorities for this company
        if ($role_id == '1' || $role_id == '2') {
            // Get all authority IDs for this company
            $result = $CI->db->select('id')
                ->where('company_id', $company_id)
                ->where('status', '1')
                ->where('is_delete', '0')
                ->get('authority')
                ->result();
            return array_column($result, 'id');
        }
        
        // User role gets only assigned authorities for this company
        $result = $CI->db->select('authority_id')
            ->where('user_id', $user_id)
            ->where('company_id', $company_id)
            ->get('user_authorities')
            ->result();
        return array_column($result, 'authority_id');
    }
}

/**
 * Get list of document type IDs the current user can access within a specific company
 * This is the new company-scoped version
 * 
 * @param int $company_id The company ID to filter by
 * @return array Array of document type IDs
 */
if (!function_exists('get_allowed_document_types_by_company')) {
    function get_allowed_document_types_by_company($company_id) {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id');
        
        if (empty($role_id) || empty($user_id) || empty($company_id)) {
            return [];
        }
        
        // Super Admin and Admin see all document types for this company
        if ($role_id == '1' || $role_id == '2') {
            // Get all document type IDs for this company
            $result = $CI->db->select('id')
                ->where('company_id', $company_id)
                ->where('status', '1')
                ->get('sub_type')
                ->result();
            return array_column($result, 'id');
        }
        
        // User role gets only assigned document types for this company
        $result = $CI->db->select('type_id')
            ->where('user_id', $user_id)
            ->where('company_id', $company_id)
            ->get('user_document_types')
            ->result();
        return array_column($result, 'type_id');
    }
}

/**
 * Get list of document type IDs the current user can access
 * 
 * @param int|null $company_id Optional company ID to filter by
 * @return array Array of document type IDs
 */
if (!function_exists('get_allowed_document_types')) {
    function get_allowed_document_types($company_id = null) {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id'); // Fixed: was 'user_id', should be 'id'
        
        if (empty($role_id) || empty($user_id)) {
            return [];
        }
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        // Super Admin and Admin get all document types
        if ($role_id == '1' || $role_id == '2') {
            return $CI->Permission_model->get_all_document_type_ids();
        }
        
        // User role gets only assigned document types
        return $CI->Permission_model->get_user_document_type_ids($user_id);
    }
}

/**
 * Check if user can access a specific authority
 * 
 * @param int $authority_id The authority ID to check
 * @param int|null $company_id Optional company ID context
 * @return bool True if user has access
 */
if (!function_exists('has_authority_access')) {
    function has_authority_access($authority_id, $company_id = null) {
        $allowed = get_allowed_authorities($company_id);
        return in_array($authority_id, $allowed);
    }
}

/**
 * Check if user can access a specific document type
 * 
 * @param int $type_id The document type ID to check
 * @param int|null $company_id Optional company ID context
 * @return bool True if user has access
 */
if (!function_exists('has_document_type_access')) {
    function has_document_type_access($type_id, $company_id = null) {
        $allowed = get_allowed_document_types($company_id);
        return in_array($type_id, $allowed);
    }
}

/**
 * Get current user's role ID
 * 
 * @return int|null Role ID or null if not logged in
 */
if (!function_exists('get_user_role')) {
    function get_user_role() {
        $CI =& get_instance();
        return $CI->session->userdata('role_id');
    }
}

/**
 * Check if current user is Super Admin
 * 
 * @return bool True if Super Admin
 */
if (!function_exists('is_super_admin')) {
    function is_super_admin() {
        return get_user_role() == '1';
    }
}

/**
 * Check if current user is Admin
 * 
 * @return bool True if Admin
 */
if (!function_exists('is_admin')) {
    function is_admin() {
        return get_user_role() == '2';
    }
}

/**
 * Check if current user is regular User
 * 
 * @return bool True if User
 */
if (!function_exists('is_user')) {
    function is_user() {
        return get_user_role() == '3';
    }
}

/**
 * Check if current user has only one company assigned
 * Super Admin always returns false (has access to all)
 * 
 * @return bool True if user has exactly one company
 */
if (!function_exists('has_single_company')) {
    function has_single_company() {
        // Super Admin has access to all companies
        if (is_super_admin()) {
            return false;
        }
        
        $companies = get_allowed_companies();
        return count($companies) === 1;
    }
}

/**
 * Get the single company ID if user has only one company
 * Returns null if user has multiple companies or is Super Admin
 * 
 * @return int|null The single company ID or null
 */
if (!function_exists('get_single_company_id')) {
    function get_single_company_id() {
        if (!has_single_company()) {
            return null;
        }
        
        $companies = get_allowed_companies();
        return !empty($companies) ? (int)$companies[0] : null;
    }
}

/**
 * Get single company details if user has only one company
 * 
 * @return object|null Company object or null
 */
if (!function_exists('get_single_company')) {
    function get_single_company() {
        $company_id = get_single_company_id();
        
        if (!$company_id) {
            return null;
        }
        
        $CI =& get_instance();
        return $CI->db->get_where('company', ['id' => $company_id])->row();
    }
}

// =====================================================
// USER-LEVEL PERMISSION CHECKS (View/Add-Edit/Delete)
// =====================================================

/**
 * Check if current user can view content
 * Combines role-level and user-level permissions
 * 
 * @return bool True if user can view
 */
if (!function_exists('can_view')) {
    function can_view() {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id');
        
        if (empty($role_id) || empty($user_id)) {
            return false;
        }
        
        // Super Admin always has full access
        if ($role_id == '1') {
            return true;
        }
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        return $CI->Permission_model->can_user_view($user_id, $role_id);
    }
}

/**
 * Check if current user can add/edit content
 * Combines role-level and user-level permissions
 * 
 * @return bool True if user can add/edit
 */
if (!function_exists('can_edit')) {
    function can_edit() {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id');
        
        if (empty($role_id) || empty($user_id)) {
            return false;
        }
        
        // Super Admin always has full access
        if ($role_id == '1') {
            return true;
        }
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        return $CI->Permission_model->can_user_edit($user_id, $role_id);
    }
}

/**
 * Check if current user can delete content
 * Combines role-level and user-level permissions
 * Note: Users (role 3) can never delete regardless of settings
 * 
 * @return bool True if user can delete
 */
if (!function_exists('can_delete')) {
    function can_delete() {
        $CI =& get_instance();
        
        $role_id = $CI->session->userdata('role_id');
        $user_id = $CI->session->userdata('id');
        
        if (empty($role_id) || empty($user_id)) {
            return false;
        }
        
        // Super Admin always has full access
        if ($role_id == '1') {
            return true;
        }
        
        // Users (role 3) can NEVER delete
        if ($role_id == '3') {
            return false;
        }
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        return $CI->Permission_model->can_user_delete($user_id, $role_id);
    }
}

/**
 * Get current user's permission flags
 * 
 * @return array Array with can_view, can_edit, can_delete flags
 */
if (!function_exists('get_user_permission_flags')) {
    function get_user_permission_flags() {
        return [
            'can_view' => can_view(),
            'can_edit' => can_edit(),
            'can_delete' => can_delete()
        ];
    }
}

/**
 * Require edit permission or show error
 * 
 * @param string $redirect_url URL to redirect to if permission denied
 * @return void
 */
if (!function_exists('require_edit_permission')) {
    function require_edit_permission($redirect_url = 'dashboard') {
        if (!can_edit()) {
            $CI =& get_instance();
            
            // For AJAX requests, return JSON error
            if ($CI->input->is_ajax_request()) {
                echo json_encode(['success' => false, 'message' => 'You do not have permission to add or edit.']);
                exit;
            }
            
            $CI->session->set_flashdata('message_type', 'error');
            $CI->session->set_flashdata('message_name', 'You do not have permission to add or edit.');
            redirect($redirect_url);
        }
    }
}

/**
 * Require delete permission or show error
 * 
 * @param string $redirect_url URL to redirect to if permission denied
 * @return void
 */
if (!function_exists('require_delete_permission')) {
    function require_delete_permission($redirect_url = 'dashboard') {
        if (!can_delete()) {
            $CI =& get_instance();
            
            // For AJAX requests, return JSON error
            if ($CI->input->is_ajax_request()) {
                echo json_encode(['success' => false, 'message' => 'You do not have permission to delete.']);
                exit;
            }
            
            $CI->session->set_flashdata('message_type', 'error');
            $CI->session->set_flashdata('message_name', 'You do not have permission to delete.');
            redirect($redirect_url);
        }
    }
}

/**
 * Require a permission or redirect with error
 * 
 * @param string $permission_key The required permission
 * @param string $redirect_url URL to redirect to if permission denied
 * @return void
 */
if (!function_exists('require_permission')) {
    function require_permission($permission_key, $redirect_url = 'dashboard') {
        if (!can($permission_key)) {
            $CI =& get_instance();
            $CI->session->set_flashdata('message_type', 'error');
            $CI->session->set_flashdata('message_name', 'You do not have permission to access this feature.');
            redirect($redirect_url);
        }
    }
}

/**
 * Require company access or redirect with error
 * 
 * @param int $company_id The required company ID
 * @param string $redirect_url URL to redirect to if access denied
 * @return void
 */
if (!function_exists('require_company_access')) {
    function require_company_access($company_id, $redirect_url = 'company/companies') {
        if (!has_company_access($company_id)) {
            $CI =& get_instance();
            $CI->session->set_flashdata('message_type', 'error');
            $CI->session->set_flashdata('message_name', 'You do not have access to this company.');
            redirect($redirect_url);
        }
    }
}

/**
 * Get enabled document heads for a company
 * 
 * @param int $company_id The company ID
 * @param int|null $authority_id Optional authority filter
 * @return array Array of document heads with company-specific settings
 */
if (!function_exists('get_company_document_heads')) {
    function get_company_document_heads($company_id, $authority_id = null) {
        $CI =& get_instance();
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        return $CI->Permission_model->get_company_document_heads($company_id, $authority_id);
    }
}

/**
 * Get enabled documents for a company and document type
 * 
 * @param int $company_id The company ID
 * @param int $type_id The document type ID
 * @return array Array of documents with company-specific settings
 */
if (!function_exists('get_company_documents')) {
    function get_company_documents($company_id, $type_id) {
        $CI =& get_instance();
        
        if (!isset($CI->Permission_model)) {
            $CI->load->model('Permission_model');
        }
        
        return $CI->Permission_model->get_company_documents($company_id, $type_id);
    }
}

/**
 * Get count of pending document heads across all companies user can access
 * Used for showing notification badge on menu
 * 
 * @return int Total pending count
 */
if (!function_exists('get_pending_doc_heads_count')) {
    function get_pending_doc_heads_count() {
        try {
            $CI =& get_instance();
            
            $role_id = $CI->session->userdata('role_id');
            
            // Only show for Super Admin and Admin roles
            if (!in_array($role_id, ['1', '2'])) {
                return 0;
            }
            
            if (!isset($CI->Permission_model)) {
                $CI->load->model('Permission_model');
            }
            
            // Get companies user can access
            $company_ids = get_allowed_companies();
            
            if (empty($company_ids) || !is_array($company_ids)) {
                return 0;
            }
            
            return (int) $CI->Permission_model->get_total_pending_doc_heads($company_ids);
        } catch (Exception $e) {
            log_message('error', 'get_pending_doc_heads_count error: ' . $e->getMessage());
            return 0;
        }
    }
}

/**
 * Normalize a name for duplicate comparison
 * 
 * Removes all non-alphanumeric characters and converts to lowercase.
 * This allows comparing names like "GST-Monthly" and "GST Monthly" as duplicates.
 * 
 * @param string $name The name to normalize
 * @return string The normalized name (lowercase, alphanumeric only)
 * 
 * Examples:
 *   "GST-Monthly" → "gstmonthly"
 *   "GSTR/1" → "gstr1"
 *   "PF Challan's" → "pfchallans"
 *   "ESI - Return" → "esireturn"
 */
/**
 * Validate name field - only allow letters, numbers, spaces, and - / '
 * 
 * @param string $name The name to validate
 * @return array ['valid' => bool, 'message' => string]
 */
if (!function_exists('validate_name_characters')) {
    function validate_name_characters($name) {
        // Only allow: letters, numbers, spaces, hyphen (-), forward slash (/), and single quote (')
        if (preg_match("/^[a-zA-Z0-9\s\-\/']+$/", $name)) {
            return ['valid' => true, 'message' => ''];
        }
        return [
            'valid' => false, 
            'message' => 'Name can only contain letters, numbers, spaces, and these special characters: - / \''
        ];
    }
}

if (!function_exists('normalize_name')) {
    function normalize_name($name) {
        // Remove all characters except letters and numbers
        $normalized = preg_replace('/[^a-zA-Z0-9]/', '', $name);
        // Convert to lowercase for case-insensitive comparison
        return strtolower($normalized);
    }
}

/**
 * Check if a name already exists in a table (case-insensitive, ignoring special chars)
 * 
 * @param string $table The database table name
 * @param string $column The column to check
 * @param string $name The name to check for duplicates
 * @param int|null $exclude_id ID to exclude (for edit operations)
 * @param array $extra_conditions Additional WHERE conditions (e.g., ['status' => '1'])
 * @return bool True if duplicate exists, false otherwise
 */
if (!function_exists('check_duplicate_name')) {
    function check_duplicate_name($table, $column, $name, $exclude_id = null, $extra_conditions = []) {
        $CI =& get_instance();
        
        $normalized_input = normalize_name($name);
        
        if (empty($normalized_input)) {
            return false;
        }
        
        // Build query to get all active records and compare normalized names
        $CI->db->select('id, ' . $column);
        $CI->db->from($table);
        
        // Apply extra conditions
        foreach ($extra_conditions as $key => $value) {
            $CI->db->where($key, $value);
        }
        
        // Exclude current ID if provided (for edit)
        if ($exclude_id) {
            $CI->db->where('id !=', $exclude_id);
        }
        
        $query = $CI->db->get();
        
        foreach ($query->result() as $row) {
            $existing_normalized = normalize_name($row->$column);
            if ($existing_normalized === $normalized_input) {
                return true; // Duplicate found
            }
        }
        
        return false;
    }
}

