/home/edulekha/crm.edulekha.com/modules/appointly/controllers/Services.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');

class Services extends AdminController
{
    public function __construct()
    {
        parent::__construct();
        $this->load->model('service_model');
        $this->load->model('staff_model');
    }

    public function index()
    {
        if (!staff_can('view', 'appointments')) {
            access_denied();
        }

        $data['title'] = _l('appointly_services');

        $this->load->view('services/manage', $data);
    }

    /**
     * Edit service or add new one
     *
     * @param integer $id
     */
    public function service($id = '')
    {
        if (!staff_can('view', 'appointments')) {
            access_denied();
        }
        if (isset($id)) {
            $data['is_service_in_use'] = $this->service_model->is_service_in_use($id);
        } else {
            $data['is_service_in_use'] = false;
        }

        if ($this->input->post()) {
            $data = $this->input->post();

            // Handle service providers
            $providers = [];
            $primary_provider = null;

            if (!empty($data['staff_members'])) {
                $providers = $data['staff_members'];
                unset($data['staff_members']);
            }

            if (!empty($data['primary_provider'])) {
                $primary_provider = $data['primary_provider'];
                unset($data['primary_provider']);
            }

            // Handle buffer times
            $data['buffer_before'] = $data['buffer_before'] ?? 0;
            $data['buffer_after'] = $data['buffer_after'] ?? 0;

            // Check if service is in use and handle active status accordingly
            if ($id !== '' && $this->service_model->is_service_in_use($id)) {
                $existing = $this->service_model->get($id);

                // Check if existing service was found
                if (!$existing) {
                    echo json_encode([
                        'success' => false,
                        'message' => _l('service_not_found')
                    ]);
                    die();
                }

                // For services in use, show warning but allow updates (except disabling)
                $data['active'] = $existing->active; // Keep existing active status

                // If trying to disable a service that's in use, return error
                if (isset($data['active']) && $data['active'] != $existing->active && $data['active'] == '0') {
                    echo json_encode([
                        'success' => false,
                        'message' => _l('appointly_service_in_use_warning')
                    ]);
                    die();
                }

                // Show warning that service is in use but allow update
                $service_in_use_warning = true;
            } else {
                $data['active'] = isset($data['active']) && $data['active'] == '1' ? 1 : 0;
                $service_in_use_warning = false;
            }

            if ($id == '') {
                // Adding new service
                $service_id = $this->service_model->add($data);
                if ($service_id) {
                    // Update service providers
                    if (!empty($providers)) {
                        $this->service_model->update_service_providers($service_id, $providers, $primary_provider);
                    }

                    echo json_encode([
                        'success' => true,
                        'message' => _l('appointly_service_add_success', _l('service')),
                        'id' => $service_id
                    ]);
                } else {
                    echo json_encode([
                        'success' => false,
                        'message' => _l('error_adding_service')
                    ]);
                }
            } else {
                // Updating existing service
                $success = $this->service_model->update($id, $data);
                if ($success) {
                    // Update service providers
                    if (!empty($providers)) {
                        $this->service_model->update_service_providers($id, $providers, $primary_provider);
                    }

                    $message = _l('appointly_service_edit_success', _l('service'));
                    if (isset($service_in_use_warning) && $service_in_use_warning) {
                        $message .= ' ' . _l('appointly_service_in_use_warning');
                    }

                    echo json_encode([
                        'success' => true,
                        'message' => $message,
                        'id' => $id,
                        'warning' => isset($service_in_use_warning) ? $service_in_use_warning : false
                    ]);
                } else {
                    echo json_encode([
                        'success' => false,
                        'message' => _l('error_updating_service')
                    ]);
                }
            }
            die();
        }

        if ($id == '') {
            $title = _l('add_new', _l('service_lowercase'));
            $data['service_is_active_checked'] = null;
            $data['service'] = new stdClass();
            $data['service']->name = '';
            $data['service']->description = '';
            $data['service']->duration = 60;
            $data['service']->price = 0;
            $data['service']->color = '#28B8DA';
            $data['service']->active = 1;
            $data['service']->buffer_before = 0;
            $data['service']->buffer_after = 0;
            $data['service']->staff_members = [];
            $data['service']->working_hours = [];
        } else {
            $service = $this->service_model->get($id);

            // Check if service exists
            if (!$service) {
                show_404();
                return;
            }

            $data['service'] = $service;
            $title = _l('edit', _l('service_lowercase'));
            $data['service_is_active_checked'] = $service->active == 1 ? 'checked' : '';
        }

        $data['staff_members'] = $this->staff_model->get('', ['active' => 1]);
        $data['title'] = $title;
        $this->load->view('services/service', $data);
    }

    public function delete($id)
    {
        if (!staff_can('delete', 'appointments')) {
            ajax_access_denied();
        }

        // Check if service is in use
        if ($this->service_model->is_service_in_use($id)) {
            echo json_encode([
                'success' => false,
                'message' => _l('appointly_service_in_use_warning')
            ]);
            return;
        }

        $response = [
            'success' => $this->service_model->delete($id),
            'message' => _l('appointly_service_delete_success')
        ];

        echo json_encode($response);
    }

    public function table()
    {
        if (!staff_can('view', 'appointments')) {
            ajax_access_denied();
        }


        $this->app->get_table_data(module_views_path('appointly', 'tables/services'));
    }

    public function change_status($id, $status)
    {
        if (!staff_can('edit', 'appointments')) {
            ajax_access_denied();
        }

        // Check if service is in use
        if ($this->service_model->is_service_in_use($id)) {
            echo json_encode([
                'success' => false,
                'message' => _l('appointly_service_in_use_warning')
            ]);
            return;
        }

        $success = $this->service_model->change_status($id, $status);

        echo json_encode([
            'success' => $success,
            'message' => $success
                ? _l('service_status_changed_success')
                : _l('service_status_changed_fail')
        ]);
    }

    public function get_working_hours($service_id)
    {
        // Load the model if not already loaded
        if (!isset($this->appointly_model)) {
            $this->load->model('appointly/appointly_model');
        }

        // Get service provider information
        $this->db->select('staff_id, is_primary');
        $this->db->from(db_prefix() . 'appointly_service_staff');
        $this->db->where('service_id', $service_id);
        $this->db->where('is_primary', 1);
        $primary_provider = $this->db->get()->row();

        $staff_id = $primary_provider ? $primary_provider->staff_id : null;

        if ($staff_id) {
            // Get staff working hours
            $working_hours = $this->appointly_model->get_staff_working_hours($staff_id);
            echo json_encode($working_hours);
        } else {
            // Fallback to company schedule
            $company_schedule = $this->appointly_model->get_company_schedule();
            echo json_encode($company_schedule);
        }
    }


    /**
     * Get service duration by service ID
     * 
     * @param int $service_id
     * @return int
     */
    public function get_service_duration($service_id)
    {
        $this->db->select('duration');
        $this->db->where('id', $service_id);
        $service = $this->db->get(db_prefix() . 'appointly_services')->row();

        return $service ? $service->duration : 60; // Default to 60 minutes if not found
    }

    public function get_service_details()
    {
        if (!$this->input->is_ajax_request()) {
            show_404();
        }

        $service_id = $this->input->post('service_id');

        if (!$service_id) {
            echo json_encode([
                'success' => false,
                'message' => 'Service ID is required'
            ]);
            die();
        }

        // Get service details
        $service = $this->service_model->get($service_id);

        // Get staff members assigned to this service
        $providers = [];
        if ($service && !empty($service->staff_members)) {
            $staff_members = is_array($service->staff_members) ? $service->staff_members : json_decode($service->staff_members, true);

            if (!empty($staff_members)) {
                $this->db->select('staffid, firstname, lastname');
                $this->db->from(db_prefix() . 'staff');
                $this->db->where_in('staffid', $staff_members);
                $this->db->where('active', 1);
                $providers = $this->db->get()->result_array();
            }
        }

        if (!$service) {
            echo json_encode([
                'success' => false,
                'message' => 'Service not found'
            ]);
            die();
        }

        echo json_encode([
            'success' => true,
            'data' => [
                'service' => $service,
                'providers' => $providers
            ]
        ]);
        die();
    }

    public function get_staff_schedule()
    {
        if (!$this->input->is_ajax_request()) {
            show_404();
        }

        $staff_id = $this->input->post('staff_id');

        // Use the helper function
        $result = appointly_get_staff_schedule($staff_id);

        // Return the result as JSON
        echo json_encode($result);
    }

    /**
     * Get service staff (admin variant)
     *
     * This method returns staff members assigned to a service
     * Used by the admin appointment modal
     *
     * @return void
     */
    public function get_service_staff()
    {
        if (!$this->input->is_ajax_request()) {
            show_404();
        }

        $service_id = $this->input->post('service_id');

        // Use the helper function
        $result = appointly_get_service_staff($service_id);

        // Return the result as JSON
        echo json_encode($result);
    }

    /**
     * Display and manage company schedule
     */
    public function company_schedule()
    {
        if (!staff_can('view', 'appointments')) {
            access_denied();
        }
        if ($this->input->post()) {
            // Handle form submission
            $schedule_data = $this->input->post('company_schedule');

            // Load model
            $this->load->model('appointly/appointly_model');

            // Process and save the schedule data
            $schedule = [];
            foreach ($schedule_data as $day => $hours) {
                // Check for value "1" for is_enabled (checkbox checked)
                $is_enabled = isset($hours['is_enabled']) && $hours['is_enabled'] == 1;

                // Default values as fallback
                $start_time = '09:00';
                $end_time = '17:00';

                // Always use submitted times if they are set, regardless of enabled status
                // This preserves the user's time choices even when day is disabled
                if (isset($hours['start_time']) && !empty($hours['start_time'])) {
                    $start_time = $hours['start_time'];
                }
                if (isset($hours['end_time']) && !empty($hours['end_time'])) {
                    $end_time = $hours['end_time'];
                }

                $schedule[$day] = [
                    'start_time' => $start_time,
                    'end_time' => $end_time,
                    'is_enabled' => $is_enabled ? 1 : 0
                ];
            }

            $success = $this->appointly_model->save_company_schedule($schedule);

            if ($success) {
                set_alert('success', _l('settings_updated'));
            } else {
                set_alert('warning', _l('settings_update_failed'));
            }

            redirect(admin_url('appointly/services/company_schedule'));
        }

        $data['title'] = _l('appointly_company_schedule');
        $this->load->view('settings/company_schedule', $data);
    }

    /**
     * Manage staff working hours
     *
     * @param int $staff_id Optional staff ID
     */
    public function staff_working_hours($staff_id = null)
    {
        // Staff can always view/edit their own working hours
        // Admin or those with edit permission can view/edit anyone's hours
        if (!staff_can('edit', 'appointments') && $staff_id != get_staff_user_id()) {
            access_denied('appointments');
        }

        // If no staff ID is provided, use the current user
        if (!$staff_id) {
            $staff_id = get_staff_user_id();
        }

        if ($this->input->post()) {
            // Handle form submission
            $working_hours_data = $this->input->post('working_hours');

            // Load model
            if (!isset($this->appointly_model)) {
                $this->load->model('appointly/appointly_model');
            }

            // Process and save the working hours data
            $working_hours = [];
            foreach ($working_hours_data as $day => $hours) {
                // Check for value "1" for is_available (checkbox checked)
                $is_available = isset($hours['is_available']) && $hours['is_available'] == 1;

                // Check for use_company_schedule checkbox
                $use_company_schedule = isset($hours['use_company_schedule']) && $hours['use_company_schedule'] == 1;

                // Default values as fallback
                $start_time = '09:00';
                $end_time = '17:00';

                // Always use submitted times if they are set, regardless of availability
                // This preserves the user's time choices even when day is disabled
                if (isset($hours['start_time']) && !empty($hours['start_time'])) {
                    $start_time = $hours['start_time'];
                }
                if (isset($hours['end_time']) && !empty($hours['end_time'])) {
                    $end_time = $hours['end_time'];
                }

                $working_hours[$day] = [
                    'start_time' => $start_time,
                    'end_time' => $end_time,
                    'is_available' => $is_available ? 1 : 0,
                    'use_company_schedule' => $use_company_schedule ? 1 : 0
                ];
            }

            $success = $this->appointly_model->save_staff_working_hours($staff_id, $working_hours);

            if ($success) {
                set_alert('success', _l('settings_updated'));
            } else {
                set_alert('warning', _l('settings_update_failed'));
            }

            redirect(admin_url('appointly/services/staff_working_hours/' . $staff_id));
        }

        // Get staff data
        $staff = $this->staff_model->get($staff_id);
        if (!$staff) {
            show_404();
        }

        // Load working hours from database
        $this->load->model('appointly/appointly_model');
        $working_hours = $this->appointly_model->get_staff_working_hours($staff_id);

        // Pass data to view
        if ($staff && (!empty($staff->firstname) || !empty($staff->lastname))) {
            $data['title'] = _l('appointly_staff_working_hours') . ' - ' . $staff->firstname . ' ' . $staff->lastname;
        } else {
            $data['title'] = _l('appointly_staff_working_hours');
        }
        $data['staff'] = $staff;
        $data['working_hours'] = $working_hours;
        $data['staff_members'] = $this->staff_model->get('', ['active' => 1]);

        $this->load->view('settings/staff_working_hours', $data);
    }

    /**
     * Get service available slots
     * 
     * Used by the appointment booking form to show available slots
     * for a specific service on a specific date
     */
    public function get_available_slots()
    {
        if (!$this->input->is_ajax_request()) {
            show_404();
        }

        $service_id = $this->input->post('service_id');
        $date = $this->input->post('date');
        $provider_id = $this->input->post('provider_id');

        if (!$service_id || !$date) {
            echo json_encode([
                'success' => false,
                'message' => 'Service ID and date are required'
            ]);
            die();
        }

        // If no provider ID is specified, try to get the primary provider
        if (!$provider_id) {
            $service = $this->service_model->get($service_id);
            if ($service && isset($service->staff_members) && !empty($service->staff_members)) {
                if (is_string($service->staff_members)) {
                    $staff_members = json_decode($service->staff_members, true);
                    if (!empty($staff_members)) {
                        $provider_id = $staff_members[0];
                    }
                } else if (is_array($service->staff_members)) {
                    $provider_id = $service->staff_members[0];
                }
            }
        }

        if (!$provider_id) {
            echo json_encode([
                'success' => false,
                'message' => 'No provider available for this service'
            ]);
            die();
        }

        // Load model
        $this->load->model('appointly/appointly_model');

        // Get available slots
        $slots = $this->appointly_model->get_available_time_slots($provider_id, $date, $service_id);

        echo json_encode([
            'success' => true,
            'data' => [
                'slots' => $slots
            ]
        ]);
        die();
    }

    /**
     * Check if service is in use
     * 
     * @param int $service_id
     * @return json
     */
    public function is_service_in_use($service_id)
    {
        $this->load->model('appointly/service_model');
        $is_in_use = $this->service_model->is_service_in_use($service_id);

        echo json_encode([
            'success' => true,
            'in_use' => $is_in_use
        ]);
    }

    /**
     * Save services availability for the external booking form
     * Called via AJAX from the services_selection_settings_js function
     * 
     * @return void
     */
    public function save_service_availability_ajax()
    {
        if (!$this->input->is_ajax_request()) {
            show_404();
        }

        if (!staff_can('edit', 'appointments')) {
            ajax_access_denied();
        }

        $services = $this->input->post('services');

        if ($services === null) {
            echo json_encode([
                'success' => false,
                'message' => 'No services data provided'
            ]);
            die();
        }

        // Validate that we have valid JSON
        if (!json_decode($services)) {
            echo json_encode([
                'success' => false,
                'message' => 'Invalid services data format'
            ]);
            die();
        }

        $success = update_option('appointments_booking_services_availability', $services);

        echo json_encode([
            'success' => $success,
            'message' => $success
                ? _l('services_availability_updated_successfully')
                : _l('services_availability_update_failed')
        ]);
        die();
    }
}