<?php
/**
 * Settings Service
 *
 * Manages global plugin settings including email configuration
 *
 * @package NemtlyBooking
 * @since   PBOOKING_SINCE
 */

namespace NemtlyBooking\Services;

/**
 * Settings Service class
 *
 * Handles global plugin settings and configuration
 *
 * @since PBOOKING_SINCE
 */
class Settings_Service {

    /**
     * Settings option name
     *
     * @since PBOOKING_SINCE
     *
     * @var string
     */
    private $option_name = 'nemtly_booking_settings';

    /**
     * Default settings
     *
     * @since PBOOKING_SINCE
     *
     * @var array
     */
    private $default_settings = [
        // Email Settings
        'email_notifications_enabled' => true,
        'admin_email'                 => '',
        'from_name'                   => '',
        'from_email'                  => '',
        'confirmation_subject'        => 'Booking Confirmation - {event_title}',
        'confirmation_message'        => '',
        'reminder_enabled'            => false,
        'reminder_hours'              => 24,
        'reminder_subject'            => 'Reminder: {event_title} tomorrow',
        'reminder_message'            => '',

        // Payment Settings
        'stripe_publishable_key'      => '',
        'stripe_secret_key'           => '',
        'stripe_webhook_secret'       => '',
        'stripe_webhook_url'          => '',
        'currency'                    => 'USD',
        'accept_stripe'               => true,
        'accept_manual_payment'       => false,
        'manual_payment_label'        => '',
        'manual_payment_instructions' => '',

        // Booking Settings
        'default_booking_status'      => 'confirmed',
        'cancellation_deadline'       => 24, // hours

        // Page Settings — IDs of the WordPress pages hosting each shortcode.
        // 0 means "not selected"; consumers fall back to a search-by-shortcode
        // or omit the link entirely.
        'dashboard_page_id'           => 0,

        // Business Hours — global default availability for new slot-based events.
        'business_hours'              => [
            'mon' => [
				[
					'start' => '09:00',
					'end'   => '17:00',
				],
			],
            'tue' => [
				[
					'start' => '09:00',
					'end'   => '17:00',
				],
			],
            'wed' => [
				[
					'start' => '09:00',
					'end'   => '17:00',
				],
			],
            'thu' => [
				[
					'start' => '09:00',
					'end'   => '17:00',
				],
			],
            'fri' => [
				[
					'start' => '09:00',
					'end'   => '17:00',
				],
			],
            'sat' => [],
            'sun' => [],
        ],

        // CAPTCHA Settings
        'captcha_type'                => 'disabled',
        'turnstile_site_key'          => '',
        'turnstile_secret_key'        => '',
    ];

    /**
     * Get all settings
     *
     * @since PBOOKING_SINCE
     *
     * @return array Settings array
     */
    public function get_settings() {
        $settings = get_option( $this->option_name, [] );

        // Merge with defaults to ensure all settings exist
        return wp_parse_args( $settings, $this->default_settings );
    }

    /**
     * Get a specific setting value
     *
     * @since PBOOKING_SINCE
     *
     * @param string $key           Setting key
     * @param mixed  $default_value Default value if setting doesn't exist
     *
     * @return mixed Setting value
     */
    public function get_setting( $key, $default_value = null ) {
        $settings = $this->get_settings();

        if ( isset( $settings[ $key ] ) ) {
            return $settings[ $key ];
        }

        return null !== $default_value ? $default_value : ( $this->default_settings[ $key ] ?? null );
    }

    /**
     * Update settings
     *
     * @since PBOOKING_SINCE
     *
     * @param array $new_settings New settings array
     *
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    public function update_settings( $new_settings ) {
        // Validate settings
        $validation_result = $this->validate_settings( $new_settings );
        if ( is_wp_error( $validation_result ) ) {
            return $validation_result;
        }

        // Get current settings
        $current_settings = $this->get_settings();

        // Merge with current settings
        $updated_settings = array_merge( $current_settings, $new_settings );

        // Sanitize settings
        $sanitized_settings = $this->sanitize_settings( $updated_settings );

        // Save settings
        $saved = update_option( $this->option_name, $sanitized_settings );

        if ( ! $saved ) {
            return new \WP_Error(
                'settings_save_failed',
                __( 'Failed to save settings', 'nemtly-booking' )
            );
        }

        // Dispatch settings updated event
        do_action( 'nemtly_booking_settings_updated', $sanitized_settings, $current_settings );

        return true;
    }

    /**
     * Update a single setting
     *
     * @since PBOOKING_SINCE
     *
     * @param string $key   Setting key
     * @param mixed  $value Setting value
     *
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    public function update_setting( $key, $value ) {
        return $this->update_settings( [ $key => $value ] );
    }

    /**
     * Reset settings to defaults
     *
     * @since PBOOKING_SINCE
     *
     * @return bool True on success, false on failure
     */
    public function reset_settings() {
        $reset = update_option( $this->option_name, $this->default_settings );

        if ( $reset ) {
            do_action( 'nemtly_booking_settings_reset', $this->default_settings );
        }

        return $reset;
    }

    /**
     * Get email settings
     *
     * @since PBOOKING_SINCE
     *
     * @return array Email settings
     */
    public function get_email_settings() {
        $settings = $this->get_settings();

        return [
            'notifications_enabled' => $settings['email_notifications_enabled'],
            'admin_email'           => ! empty( $settings['admin_email'] ) ? $settings['admin_email'] : get_option( 'admin_email' ),
            'from_name'             => ! empty( $settings['from_name'] ) ? $settings['from_name'] : get_option( 'blogname' ),
            'from_email'            => ! empty( $settings['from_email'] ) ? $settings['from_email'] : get_option( 'admin_email' ),
            'confirmation_subject'  => $settings['confirmation_subject'],
            'confirmation_message'  => ! empty( $settings['confirmation_message'] ) ? $settings['confirmation_message'] : $this->get_default_confirmation_message(),
            'reminder_enabled'      => $settings['reminder_enabled'],
            'reminder_hours'        => $settings['reminder_hours'],
            'reminder_subject'      => $settings['reminder_subject'],
            'reminder_message'      => ! empty( $settings['reminder_message'] ) ? $settings['reminder_message'] : $this->get_default_reminder_message(),
        ];
    }

    /**
     * Validate settings
     *
     * @since PBOOKING_SINCE
     *
     * @param array $settings Settings to validate
     *
     * @return true|WP_Error True on success, WP_Error on validation failure
     */
    private function validate_settings( $settings ) {
        $errors = [];

        // Validate email settings
        if ( isset( $settings['from_email'] ) && ! empty( $settings['from_email'] ) ) {
            if ( ! is_email( $settings['from_email'] ) ) {
                $errors[] = __( 'Invalid from email address', 'nemtly-booking' );
            }
        }

        if ( isset( $settings['admin_email'] ) && ! empty( $settings['admin_email'] ) ) {
            if ( ! is_email( $settings['admin_email'] ) ) {
                $errors[] = __( 'Invalid admin email address', 'nemtly-booking' );
            }
        }

        // Validate time settings
        if ( isset( $settings['reminder_hours'] ) ) {
            $hours = intval( $settings['reminder_hours'] );
            if ( $hours < 0 || $hours > 168 ) { // Max 1 week
                $errors[] = __( 'Reminder hours must be between 0 and 168', 'nemtly-booking' );
            }
        }

        // Validate Payment Settings
        if ( ! empty( $settings['stripe_publishable_key'] ) ) {
            if ( 0 !== strpos( $settings['stripe_publishable_key'], 'pk_' ) ) {
                $errors[] = __( 'Invalid Stripe Publishable Key. It should start with "pk_"', 'nemtly-booking' );
            }
        }

        if ( ! empty( $settings['stripe_secret_key'] ) ) {
            if ( 0 !== strpos( $settings['stripe_secret_key'], 'sk_' ) && 0 !== strpos( $settings['stripe_secret_key'], 'rk_' ) ) {
                $errors[] = __( 'Invalid Stripe Secret Key. It should start with "sk_" or "rk_"', 'nemtly-booking' );
            }
        }

        if ( ! empty( $settings['stripe_webhook_secret'] ) ) {
            if ( 0 !== strpos( $settings['stripe_webhook_secret'], 'whsec_' ) ) {
                $errors[] = __( 'Invalid Stripe Webhook Secret. It should start with "whsec_"', 'nemtly-booking' );
            }
        }

        if ( ! empty( $settings['stripe_webhook_url'] ) ) {
            if ( false === filter_var( $settings['stripe_webhook_url'], FILTER_VALIDATE_URL ) ) {
                $errors[] = __( 'Invalid Webhook endpoint URL.', 'nemtly-booking' );
            }
        }

        if ( ! empty( $errors ) ) {
            return new \WP_Error( 'validation_failed', implode( '. ', $errors ) );
        }

        return true;
    }

    /**
     * Sanitize settings
     *
     * @since PBOOKING_SINCE
     *
     * @param array $settings Settings to sanitize.
     *
     * @return array Sanitized settings
     */
    private function sanitize_settings( $settings ) {
        $sanitized = [];

        foreach ( $settings as $key => $value ) {
            switch ( $key ) {
                case 'from_name':
                case 'confirmation_subject':
                case 'reminder_subject':
                    $sanitized[ $key ] = sanitize_text_field( $value );
                    break;

                case 'from_email':
                case 'admin_email':
                    $sanitized[ $key ] = sanitize_email( $value );
                    break;

                case 'confirmation_message':
                case 'reminder_message':
                    $sanitized[ $key ] = wp_kses_post( $value );
                    break;

                case 'email_notifications_enabled':
                case 'allow_guest_booking':
                case 'require_approval':
                case 'cancellation_allowed':
                case 'reminder_enabled':
                case 'accept_stripe':
                case 'accept_manual_payment':
                    $sanitized[ $key ] = (bool) $value;
                    break;

                case 'manual_payment_label':
                    $sanitized[ $key ] = sanitize_text_field( $value );
                    break;

                case 'manual_payment_instructions':
                    $sanitized[ $key ] = wp_kses_post( $value );
                    break;

                case 'reminder_hours':
                case 'cancellation_deadline':
                case 'dashboard_page_id':
                    $sanitized[ $key ] = intval( $value );
                    break;

                case 'stripe_webhook_url':
                    $sanitized[ $key ] = esc_url_raw( $value );
                    break;

                case 'timezone':
                case 'date_format':
                case 'time_format':
                case 'default_booking_status':
                    $sanitized[ $key ] = sanitize_text_field( $value );
                    break;

                case 'captcha_type':
                    $allowed           = [ 'disabled', 'text', 'turnstile' ];
                    $sanitized[ $key ] = in_array( $value, $allowed, true ) ? $value : 'disabled';
                    break;

                case 'turnstile_site_key':
                case 'turnstile_secret_key':
                    $sanitized[ $key ] = sanitize_text_field( $value );
                    break;

                case 'business_hours':
                    $sanitized[ $key ] = is_array( $value ) ? $this->sanitize_business_hours( $value ) : [];
                    break;

                default:
                    $sanitized[ $key ] = sanitize_text_field( $value );
                    break;
            }
        }

        return $sanitized;
    }

    /**
     * Get default confirmation email message
     *
     * @since PBOOKING_SINCE
     *
     * @return string Default confirmation message
     */
    private function get_default_confirmation_message() {
        return __(
            'Dear {attendee_name},

Thank you for your booking! Your reservation has been confirmed for the following event:

Event: {event_title}
Date: {event_date}
Time: {event_time}
Location: {event_location}
Booking Reference: {booking_uuid}

We look forward to seeing you at the event. If you have any questions, please don\'t hesitate to contact us.

Best regards,
{site_name}

---
This is an automated confirmation email. Please do not reply to this message.',
            'nemtly-booking'
        );
    }

    /**
     * Get default reminder email message
     *
     * @since PBOOKING_SINCE
     *
     * @return string Default reminder message
     */
    private function get_default_reminder_message() {
        return __(
            'Dear {attendee_name},

This is a friendly reminder about your upcoming event:

Event: {event_title}
Date: {event_date}
Time: {event_time}
Location: {event_location}
Booking Reference: {booking_uuid}

We look forward to seeing you tomorrow!

Best regards,
{site_name}

---
This is an automated reminder email. Please do not reply to this message.',
            'nemtly-booking'
        );
    }

    /**
     * Sanitize business hours availability structure.
     *
     * @since PBOOKING_SINCE
     *
     * @param array $hours Raw business hours data.
     *
     * @return array Sanitized business hours.
     */
    private function sanitize_business_hours( $hours ) {
        $days      = [ 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun' ];
        $sanitized = [];

        foreach ( $days as $day ) {
            $blocks = isset( $hours[ $day ] ) && is_array( $hours[ $day ] ) ? $hours[ $day ] : [];

            $sanitized_blocks = [];
            foreach ( $blocks as $block ) {
                if ( is_array( $block ) && isset( $block['start'], $block['end'] ) ) {
                    $start = sanitize_text_field( $block['start'] );
                    $end   = sanitize_text_field( $block['end'] );
                    if ( preg_match( '/^\d{2}:\d{2}$/', $start ) && preg_match( '/^\d{2}:\d{2}$/', $end ) ) {
                        $sanitized_blocks[] = [
                            'start' => $start,
                            'end'   => $end,
                        ];
                    }
                }
            }

            $sanitized[ $day ] = $sanitized_blocks;
        }

        return $sanitized;
    }
}
