<?php

namespace BookWellAB;

defined('ABSPATH') || exit;
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching

if (!class_exists('BookWellAB_Notifications')) {

    class BookWellAB_Notifications
    {

        private static $instance = null;
        private $bookwell_page = 'notifications';
        private $bwdb;

        public static function get_instance()
        {
            if (self::$instance === null) {
                self::$instance = new self();
            }
            return self::$instance;
        }

        public function __construct()
        {
            global $BOOKWELLAB;
            $this->bwdb = new BookWellAB_Database();
            $current_page = (isset($BOOKWELLAB) && $BOOKWELLAB instanceof BOOKWELL)
                ? $BOOKWELLAB->get_bookwell_admin_page()
                : '';

            if (is_admin() && $current_page == $this->bookwell_page) {
                add_filter('bookwellab_admin_script_vriable_data', [$this, 'bookwellab_admin_script_vriable_data'], 10, 2);
                add_action('bookwellab_notifications_admin_html', [$this, 'bookwellab_notifications_admin_html_func'], 10);
                add_filter('bookwellab_page_method_data', [$this, 'bookwellab_page_method_data_func'], 10, 2);
            }

            // AJAX Handlers
            add_action('wp_ajax_bookwellab_save_notifications', [$this, 'bookwellab_save_notifications_func']);
        }

        public function bookwellab_notifications_admin_html_func()
        {
            require BOOKWELLAB_HTML_PATH . 'notifications_view.php';
        }

        public function bookwellab_admin_script_vriable_data($bookwellab_admin_script_vriable_data, $page)
        {
            if ($page == $this->bookwell_page) {
                $bookwellab_admin_script_vriable_data['notification_settings'] = $this->get_notification_settings();
                $bookwellab_admin_script_vriable_data['current_notification_tab'] = 'on_approval'; // Default tab
                $bookwellab_admin_script_vriable_data['active_sub_tab'] = 'customer';
                $bookwellab_admin_script_vriable_data['settings_loader'] = false;
            }
            return $bookwellab_admin_script_vriable_data;
        }

        public function bookwellab_page_method_data_func($bookwellab_page_method_data, $page)
        {
            if ($page == $this->bookwell_page) {
                $bookwellab_page_method_data .= '
                    bwab_saveNotifications() {
                        const vuedata = this;
                        vuedata.settings_loader = true;
                        
                        var ajax_url = bookwellab_ajax_obj.ajax_url;
                        var postData = {
                            action: "bookwellab_save_notifications",
                            _wpnonce: bookwellab_ajax_obj.bookwellab_nonce,
                            settings: JSON.stringify(vuedata.notification_settings)
                        };
                        
                        axios.post(ajax_url, Qs.stringify(postData))
                        .then(function(response) {
                            vuedata.settings_loader = false;
                            if(response.data.success) {
                                vuedata.$notify({ type: "success", message: response.data.data.msg });
                            } else {
                                vuedata.$notify({ type: "error", message: response.data.data.msg });
                            }
                        }).catch(function(error) {
                            vuedata.settings_loader = false;
                            console.log(error);
                        });
                    },
                    copyToClipboard(text) {
                        navigator.clipboard.writeText(text).then(() => {
                            this.$message({
                                message: "Copied: " + text,
                                type: "success"
                            });
                        }).catch(err => {
                            console.error("Could not copy text: ", err);
                        });
                    },
                ';
            }
            return $bookwellab_page_method_data;
        }

        public static function get_default_settings()
        {
            return [
                'on_approval' => [
                    'enable' => '1',
                    'customer' => [
                        'enable' => '1',
                        'cc_email' => '',
                        'subject' => __('Appointment Approved', 'bookwellnow-appointment-booking'),
                        'message' => sprintf(
                            /* translators: 1: customer first name placeholder, 2: customer last name placeholder, 3: company name placeholder */
                            __('Dear %1$s %2$s,<br/>Your appointment has been successfully scheduled.<br/>Thank you for choosing %3$s. We look forward to serving you.<br/>Best regards,<br/>%3$s', 'bookwellnow-appointment-booking'),
                            '%customer_first_name%',
                            '%customer_last_name%',
                            '%company_name%'
                        ) . '<br/><br/>%cancel_appointment_link%',
                    ],
                    'staff' => [
                        'enable' => '1',
                        'cc_email' => '',
                        'subject' => __('New Appointment Approved', 'bookwellnow-appointment-booking'),
                        'message' => sprintf(
                            /* translators: 1: service name placeholder, 2: company name placeholder */
                            __('Hi staff,<br/>You have one confirmed %1$s appointment. The appointment is added to your schedule.<br/>Thank you,<br/>%2$s', 'bookwellnow-appointment-booking'),
                            '%service_name%',
                            '%company_name%'
                        ),
                    ]
                ],
                'on_pending' => [
                    'enable' => '1',
                    'customer' => [
                        'enable' => '1',
                        'cc_email' => '',
                        'subject' => __('Appointment Pending', 'bookwellnow-appointment-booking'),
                        'message' => sprintf(
                            /* translators: 1: customer first name placeholder, 2: customer last name placeholder, 3: service name placeholder, 4: company name placeholder */
                            __('Dear %1$s %2$s,<br/>The %3$s appointment is scheduled and it is waiting for a confirmation.<br/>Thank you for choosing %4$s,<br/>%4$s', 'bookwellnow-appointment-booking'),
                            '%customer_first_name%',
                            '%customer_last_name%',
                            '%service_name%',
                            '%company_name%'
                        ) . '<br/><br/>%cancel_appointment_link%',
                    ],
                    'staff' => [
                        'enable' => '1',
                        'cc_email' => '',
                        'subject' => __('New Appointment Pending', 'bookwellnow-appointment-booking'),
                        'message' => sprintf(
                            /* translators: 1: service name placeholder, 2: company name placeholder */
                            __('Hi staff,<br/>You have new appointment in %1$s. The appointment is waiting for a confirmation.<br/>Thank you,<br/>%2$s', 'bookwellnow-appointment-booking'),
                            '%service_name%',
                            '%company_name%'
                        ),
                    ]
                ],
                'on_cancellation' => [
                    'enable' => '1',
                    'customer' => [
                        'enable' => '1',
                        'cc_email' => '',
                        'subject' => __('Appointment Cancelled', 'bookwellnow-appointment-booking'),
                        'message' => sprintf(
                            /* translators: 1: customer first name placeholder, 2: customer last name placeholder, 3: service name placeholder, 4: company name placeholder */
                            __('Dear %1$s %2$s,<br/>The %3$s appointment, has been canceled.<br/>Thank you for choosing %4$s,<br/>%4$s', 'bookwellnow-appointment-booking'),
                            '%customer_first_name%',
                            '%customer_last_name%',
                            '%service_name%',
                            '%company_name%'
                        ),
                    ],
                    'staff' => [
                        'enable' => '1',
                        'cc_email' => '',
                        'subject' => __('Appointment Cancelled', 'bookwellnow-appointment-booking'),
                        'message' => sprintf(
                            /* translators: 1: service name placeholder, 2: company name placeholder */
                            __('Hi staff,<br/>Your %1$s appointment, has been canceled.<br/>Thank you,<br/>%2$s', 'bookwellnow-appointment-booking'),
                            '%service_name%',
                            '%company_name%'
                        ),
                    ]
                ]
            ];
        }

        /**
         * Sanitize a comma-separated CC email list.
         *
         * @param mixed $raw Raw CC string.
         * @return string
         */
        private function sanitize_cc_emails($raw)
        {
            $parts = preg_split('/\s*,\s*/', trim((string) $raw));
            $valid = array();

            foreach ($parts as $email) {
                $email = sanitize_email($email);
                if ($email !== '' && is_email($email)) {
                    $valid[] = $email;
                }
            }

            return implode(', ', $valid);
        }

        /**
         * Build HTML email headers with optional CC recipients.
         *
         * @param string $cc_email Comma-separated CC addresses.
         * @return array<int, string>
         */
        private function build_email_headers($cc_email = '')
        {
            $headers = array('Content-Type: text/html; charset=UTF-8');
            $cc_email = $this->sanitize_cc_emails($cc_email);

            if ($cc_email !== '') {
                $headers[] = 'Cc: ' . $cc_email;
            }

            return $headers;
        }

        /**
         * Sanitize notification settings while preserving safe HTML in email bodies.
         *
         * @param array $settings Raw decoded settings.
         * @return array
         */
        private function sanitize_notification_settings_payload($settings)
        {
            $defaults = self::get_default_settings();
            $sanitized = array();

            foreach ($defaults as $trigger_key => $trigger_defaults) {
                if (!isset($settings[$trigger_key]) || !is_array($settings[$trigger_key])) {
                    continue;
                }

                $trigger_input = $settings[$trigger_key];
                $sanitized[$trigger_key] = array(
                    'enable' => isset($trigger_input['enable']) ? sanitize_text_field((string) $trigger_input['enable']) : $trigger_defaults['enable'],
                );

                foreach (array('customer', 'staff') as $recipient_key) {
                    if (!isset($trigger_defaults[$recipient_key]) || !isset($trigger_input[$recipient_key]) || !is_array($trigger_input[$recipient_key])) {
                        continue;
                    }

                    $recipient_input = $trigger_input[$recipient_key];
                    $recipient_defaults = $trigger_defaults[$recipient_key];
                    $sanitized_recipient = array(
                        'enable' => isset($recipient_input['enable']) ? sanitize_text_field((string) $recipient_input['enable']) : $recipient_defaults['enable'],
                        'subject' => isset($recipient_input['subject']) ? sanitize_text_field((string) $recipient_input['subject']) : $recipient_defaults['subject'],
                        'message' => isset($recipient_input['message']) ? wp_kses_post((string) $recipient_input['message']) : $recipient_defaults['message'],
                    );

                    if (isset($recipient_defaults['cc_email'])) {
                        $sanitized_recipient['cc_email'] = isset($recipient_input['cc_email'])
                            ? $this->sanitize_cc_emails($recipient_input['cc_email'])
                            : $recipient_defaults['cc_email'];
                    }

                    $sanitized[$trigger_key][$recipient_key] = $sanitized_recipient;
                }
            }

            return $sanitized;
        }

        public function get_notification_settings()
        {
            $defaults = self::get_default_settings();

            $saved_settings = $this->bwdb->get_setting('notification_settings', []);

            if (empty($saved_settings)) {
                return $defaults;
            }

            // Merge defaults with saved settings to ensure structure
            return array_replace_recursive($defaults, $saved_settings);
        }

        public function bookwellab_save_notifications_func()
        {
            $nonce = isset($_POST['_wpnonce']) ? sanitize_text_field(wp_unslash($_POST['_wpnonce'])) : '';
            if (empty($nonce) || !wp_verify_nonce($nonce, 'bw_wp_nonce')) {
                wp_send_json_error(['msg' => __('Security check failed', 'bookwellnow-appointment-booking')]);
            }

            if (!BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => __('Permission denied', 'bookwellnow-appointment-booking')]);
            }

            // BookWellAB_Input: decoded JSON only; all keys sanitized in sanitize_notification_settings_payload() before DB write.
            $settings = BookWellAB_Input::get_post_json('settings');
            if (empty($settings)) {
                wp_send_json_error(['msg' => __('Invalid data', 'bookwellnow-appointment-booking')]);
            }
            $settings = $this->sanitize_notification_settings_payload($settings);

            $this->bwdb->update_setting('notification_settings', $settings);

            wp_send_json_success(['msg' => __('Settings saved successfully', 'bookwellnow-appointment-booking')]);
        }

        /**
         * Send Notification
         * 
         * @param string $trigger The trigger key (e.g., 'on_pending', 'on_approval')
         * @param array $appointment_data Associative array of appointment details
         */
        public function send_notification($trigger, $appointment_data)
        {
            $settings = $this->get_notification_settings();

            if (!isset($settings[$trigger]) || $settings[$trigger]['enable'] != '1') {
                return;
            }

            $general_settings = \BookWellAB\BookWellAB_Settings::get_instance()->get_settings()['general'];
            $company_name = isset($general_settings['company_name']) ? $general_settings['company_name'] : get_bloginfo('name');

            // Format Date and Time according to settings
            $date_format_setting = isset($general_settings['date_format']) ? $general_settings['date_format'] : 'Y-m-d';
            $time_format_setting = isset($general_settings['time_format']) ? $general_settings['time_format'] : 'H:i';
            
            $date_format = ($date_format_setting !== 'inherit') ? $date_format_setting : get_option('date_format');
            $time_format = ($time_format_setting !== 'inherit') ? $time_format_setting : get_option('time_format');
            
            $timestamp = strtotime($appointment_data['bw_date'] . ' ' . $appointment_data['bw_time']);
            $formatted_date = date_i18n($date_format, $timestamp);
            $formatted_time = date_i18n($time_format, $timestamp);

            // Ensure first and last name are available from the customer table if not in appointment data
            if (!isset($appointment_data['bw_customer_first_name']) || !isset($appointment_data['bw_customer_last_name']) || !isset($appointment_data['bw_appointment_hash'])) {
                global $wpdb;
                $customer_table = esc_sql($this->bwdb->get_table_name('customers'));
                $appt_table = esc_sql($this->bwdb->get_table_name('appointments'));
                $customer_id = intval($appointment_data['bw_customer_id']);
                $appt_id = intval($appointment_data['bw_appointment_id']);
                
                if (!isset($appointment_data['bw_customer_first_name']) || !isset($appointment_data['bw_customer_last_name'])) {
                    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is plugin-controlled and escaped.
                    $customer_res = $wpdb->get_row($wpdb->prepare("SELECT bw_first_name, bw_last_name FROM $customer_table WHERE bw_customer_id = %d", $customer_id), ARRAY_A);
                    if ($customer_res) {
                        $appointment_data['bw_customer_first_name'] = $customer_res['bw_first_name'];
                        $appointment_data['bw_customer_last_name'] = $customer_res['bw_last_name'];
                    }
                }

                if (!isset($appointment_data['bw_appointment_hash'])) {
                    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is plugin-controlled and escaped.
                    $appointment_data['bw_appointment_hash'] = $wpdb->get_var($wpdb->prepare("SELECT bw_appointment_hash FROM $appt_table WHERE bw_appointment_id = %d", $appt_id));
                }
            }

            $placeholders = [
                '{appointment_id}' => $appointment_data['bw_appointment_id'],
                '{customer_name}' => $appointment_data['bw_customer_name'],
                '{service_name}' => $appointment_data['bw_service_name'],
                '{staff_name}' => $appointment_data['bw_staff_name'],
                '{date}' => $formatted_date,
                '{time}' => $formatted_time,
                '{price}' => \BookWellAB\BookWellAB_Settings::get_formatted_price($appointment_data['bw_price']),
                '{company_name}' => $company_name,
                '%customer_first_name%' => $appointment_data['bw_customer_first_name'] ?? '',
                '%customer_last_name%' => $appointment_data['bw_customer_last_name'] ?? '',
                '%customer_email%' => $appointment_data['bw_customer_email'] ?? '',
                '%customer_phone%' => $appointment_data['bw_customer_phone'] ?? '',
                '%service_name%' => $appointment_data['bw_service_name'] ?? '',
                '%staff_name%' => $appointment_data['bw_staff_name'] ?? '',
                '%appointment_date%' => $formatted_date,
                '%appointment_time%' => $formatted_time,
                '%appointment_price%' => \BookWellAB\BookWellAB_Settings::get_formatted_price($appointment_data['bw_price'] ?? 0),
                '%company_name%' => $company_name,
                '%cancel_appointment_link%' => BookWellAB_Booking_Helper::get_public_cancel_appointment_link_html(
                    (int) ($appointment_data['bw_appointment_id'] ?? 0),
                    (string) ($appointment_data['bw_appointment_hash'] ?? '')
                ),
            ];

            $placeholders = apply_filters('bookwellab_notification_placeholders', $placeholders, $trigger, $appointment_data);

            // 1. Send to Customer
            if (isset($settings[$trigger]['customer']) && $settings[$trigger]['customer']['enable'] == '1') {
                $subject = $settings[$trigger]['customer']['subject'];
                $message = $settings[$trigger]['customer']['message'];

                foreach ($placeholders as $key => $value) {
                    $subject = str_replace($key, $value, $subject);
                    $message = str_replace($key, $value, $message);
                }

                $to = $appointment_data['bw_customer_email'];
                $cc_email = isset($settings[$trigger]['customer']['cc_email']) ? $settings[$trigger]['customer']['cc_email'] : '';
                $headers = $this->build_email_headers($cc_email);
                $this->send_and_log_email(
                    $to,
                    $subject,
                    $message,
                    $headers,
                    [
                        'trigger' => $trigger,
                        'recipient_type' => 'customer',
                        'appointment_id' => (int) ($appointment_data['bw_appointment_id'] ?? 0),
                        'cc_email' => $cc_email,
                    ]
                );
            }

            // 2. Send to Staff
            if (isset($settings[$trigger]['staff']) && $settings[$trigger]['staff']['enable'] == '1') {
                $subject = $settings[$trigger]['staff']['subject'];
                $message = $settings[$trigger]['staff']['message'];

                foreach ($placeholders as $key => $value) {
                    $subject = str_replace($key, $value, $subject);
                    $message = str_replace($key, $value, $message);
                }

                // Fetch Staff Email using staff_id if not in appointment data
                $staff_email = '';
                if (isset($appointment_data['bw_staff_email'])) {
                    $staff_email = $appointment_data['bw_staff_email'];
                } else {
                    global $wpdb;
                    $staff_table = esc_sql($this->bwdb->get_table_name('staffs'));
                    $staff_id = intval($appointment_data['bw_staff_id']);
                    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is plugin-controlled and escaped.
                    $staff_email = $wpdb->get_var($wpdb->prepare("SELECT bw_staff_email FROM $staff_table WHERE bw_staff_id = %d", $staff_id));
                }

                if ($staff_email) {
                    $cc_email = isset($settings[$trigger]['staff']['cc_email']) ? $settings[$trigger]['staff']['cc_email'] : '';
                    $headers = $this->build_email_headers($cc_email);
                    $this->send_and_log_email(
                        $staff_email,
                        $subject,
                        $message,
                        $headers,
                        [
                            'trigger' => $trigger,
                            'recipient_type' => 'staff',
                            'appointment_id' => (int) ($appointment_data['bw_appointment_id'] ?? 0),
                            'cc_email' => $cc_email,
                        ]
                    );
                }
            }
        }

        /**
         * Send email via wp_mail and optionally write Email Notification Debug Logs.
         *
         * @param string               $to      Recipient email.
         * @param string               $subject Email subject.
         * @param string               $message Plain/HTML body (before nl2br).
         * @param array<int, string>   $headers Email headers.
         * @param array<string, mixed> $context Log context.
         * @return bool
         */
        private function send_and_log_email($to, $subject, $message, $headers, $context = [])
        {
            $to = sanitize_email((string) $to);
            $subject = (string) $subject;
            $message = (string) $message;
            $headers = is_array($headers) ? $headers : [];
            $context = is_array($context) ? $context : [];
            $appointment_id = isset($context['appointment_id']) ? absint($context['appointment_id']) : 0;
            $trigger = isset($context['trigger']) ? sanitize_key((string) $context['trigger']) : '';
            $recipient_type = isset($context['recipient_type']) ? sanitize_key((string) $context['recipient_type']) : '';

            BookWellAB_Payment_Debug_Log::log(
                'email',
                'Send Email Notification',
                'bookwellab_email_notification',
                [
                    'trigger' => $trigger,
                    'recipient_type' => $recipient_type,
                    'to' => $to,
                    'cc_email' => isset($context['cc_email']) ? (string) $context['cc_email'] : '',
                    'subject' => $subject,
                    'message' => wp_strip_all_tags($message),
                    'appointment_id' => $appointment_id,
                ],
                $appointment_id
            );

            $mail_error = '';
            $failed_cb = static function ($error) use (&$mail_error) {
                if (is_wp_error($error)) {
                    $mail_error = $error->get_error_message();
                }
            };
            add_action('wp_mail_failed', $failed_cb);

            $sent = wp_mail($to, $subject, nl2br($message), $headers);

            remove_action('wp_mail_failed', $failed_cb);

            if ($sent) {
                BookWellAB_Payment_Debug_Log::log(
                    'email',
                    'Send Email Notification Success',
                    'bookwellab_email_notification',
                    [
                        'trigger' => $trigger,
                        'recipient_type' => $recipient_type,
                        'to' => $to,
                        'status' => 1,
                    ],
                    $appointment_id
                );
            } else {
                global $phpmailer;
                $phpmailer_error = '';
                if (isset($phpmailer) && is_object($phpmailer) && !empty($phpmailer->ErrorInfo)) {
                    $phpmailer_error = (string) $phpmailer->ErrorInfo;
                }
                BookWellAB_Payment_Debug_Log::log(
                    'email',
                    'Send Email Notification Error',
                    'bookwellab_email_notification',
                    [
                        'trigger' => $trigger,
                        'recipient_type' => $recipient_type,
                        'to' => $to,
                        'status' => 0,
                        'error' => $mail_error !== '' ? $mail_error : $phpmailer_error,
                    ],
                    $appointment_id
                );
            }

            return (bool) $sent;
        }
    }
}
// phpcs:enable
