<?php

namespace FluentBooking\App\Services;

use FluentBooking\App\Models\Booking;
use FluentBooking\App\Models\CalendarSlot;
use FluentBooking\Framework\Support\Arr;

class BookingFieldService
{
    public static function getCustomFieldsData($postedData, CalendarSlot $slot)
    {
        $customFields = self::getCustomFields($slot, true);

        $errors = [];

        $formattedValues = [];

        foreach ($customFields as $fieldKey => $customField) {
            $value = wp_unslash(Arr::get($postedData, $fieldKey));
            if (Arr::isTrue($customField, 'required')) {
                $isTerms = $customField['type'] === 'terms-and-conditions';
                $isCheckbox = $customField['type'] === 'checkbox';
                if (!$value || ($isCheckbox && $value !== 'Yes') || ($isTerms && $value !== 'Accepted')) {
                    /* translators: %s: Field label */
                    $errors[$fieldKey . '.required'] = sprintf(__('%s is required', 'fluent-booking'), $customField['label']);
                    continue;
                }
            }

            if (is_array($value)) {
                if ($customField['type'] === 'multi-select') {
                    $value = array_map(function ($item) {
                        $val = is_array($item) ? Arr::get($item, 'value') : $item;
                        return sanitize_text_field($val);
                    },$value);
                } else if ($customField['type'] === 'file') {
                    $maxField = Arr::get($customField, 'max_file_allow', 1);
                    $value = array_slice($value, 0, $maxField);
                    $value = array_map('sanitize_text_field', $value);
                } else {
                    $value = array_map('sanitize_text_field', $value);
                }
            } else if ($customField['type'] == 'textarea') {
                $value = sanitize_textarea_field($value);
            } else {
                $value = sanitize_text_field($value);
            }

            $formattedValues[$fieldKey] = $value;
        }

        if ($errors) {
            return new \WP_Error('required_field', __('Please fill up the required data', 'fluent-booking'), $errors);
        }

        return $formattedValues;
    }

    public static function getBookingFields(CalendarSlot $calendarSlot, $cached = false)
    {
        static $bookingFields = null;

        if ($cached && $bookingFields) {
            return $bookingFields;
        }

        $requiredIndexes = ['name', 'email', 'message', 'cancellation_reason', 'rescheduling_reason'];

        $defaultFields = [
            'name' => [
                'index'          => 1,
                'type'           => 'text',
                'name'           => 'name',
                'label'          => __('Your Name', 'fluent-booking'),
                'required'       => true,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => true,
                'is_visible'     => true,
                'placeholder'    => __('Your Name', 'fluent-booking'),
                'help_text'      => ''
            ],
            'email' => [
                'index'          => 2,
                'type'           => 'email',
                'name'           => 'email',
                'label'          => __('Your Email', 'fluent-booking'),
                'required'       => true,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => true,
                'is_visible'     => true,
                'placeholder'    => __('Your Email', 'fluent-booking'),
                'help_text'      => ''
            ],
            'message' => [
                'index'          => 3,
                'type'           => 'textarea',
                'name'           => 'message',
                'label'          => __('What is this meeting about?', 'fluent-booking'),
                'required'       => false,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => false,
                'help_text'      => ''
            ],
            'cancellation_reason' => [
                'index'          => 4,
                'type'           => 'textarea',
                'name'           => 'cancellation_reason',
                'label'          => __('Reason for cancellation', 'fluent-booking'),
                'placeholder'    => __('Why are you cancelling?', 'fluent-booking'),
                'required'       => true,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => false,
                'help_text'      => ''
            ],
            'rescheduling_reason' => [
                'index'          => 5,
                'type'           => 'textarea',
                'name'           => 'rescheduling_reason',
                'label'          => __('Reason for reschedule', 'fluent-booking'),
                'placeholder'    => __('Let others know why you need to reschedule', 'fluent-booking'),
                'required'       => true,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => false,
                'help_text'      => ''
            ],
        ];

        if ($calendarSlot->isGuestFieldRequired()) {
            $requiredIndexes[] = 'guests';
            $defaultFields['guests'] = [
                'index'          => 6,
                'type'           => 'multi-guests',
                'name'           => 'guests',
                'label'          => __('Additional Guests', 'fluent-booking'),
                'limit'          => 10,
                'required'       => false,
                'enabled'        => false,
                'system_defined' => true,
                'disable_alter'  => false
            ];
        }

        if ($calendarSlot->isLocationFieldRequired()) {
            $requiredIndexes[] = 'location';
            $defaultFields['location'] = [
                'index'          => 7,
                'type'           => 'radio',
                'name'           => 'location',
                'label'          => __('Location', 'fluent-booking'),
                'options'        => LocationService::getLocationOptions($calendarSlot),
                'required'       => true,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => true,
                'placeholder'    => esc_attr__('Location', 'fluent-booking')
            ];
        } else if ($calendarSlot->isPhoneRequired()) {
            $requiredIndexes[] = 'phone_number';
            $defaultFields['phone_number'] = [
                'index'          => 8,
                'type'           => 'phone',
                'name'           => 'phone_number',
                'label'          => __('Your Phone Number', 'fluent-booking'),
                'required'       => true,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => true,
                'is_sms_number'  => true,
                'help_text'      => ''
            ];
        } else if ($calendarSlot->isAddressRequired()) {
            $requiredIndexes[] = 'address';
            $defaultFields['address'] = [
                'index'          => 9,
                'type'           => 'text',
                'name'           => 'address',
                'label'          => __('Your Address', 'fluent-booking'),
                'required'       => true,
                'enabled'        => true,
                'system_defined' => true,
                'disable_alter'  => true,
                'placeholder'    => esc_attr__('Address', 'fluent-booking'),
                'help_text'      => ''
            ];
        }

        $dbFields = $calendarSlot->getMeta('booking_fields', []);

        if (!$dbFields) {
            $dbFields = array_values($defaultFields);
        }

        $existingFields = [];
        foreach ($dbFields as $dbField) {
            $name = $dbField['name'];
            $existingFields[$name] = $dbField;
        }

        if (empty($defaultFields['location'])) {
            unset($existingFields['location']);
        } else {
            if (empty($existingFields['location'])) {
                $existingFields['location'] = $defaultFields['location'];
            } else {
                $existingFields['location']['options'] = $defaultFields['location']['options'];
            }
        }

        if (empty($defaultFields['phone_number'])) {
            unset($existingFields['phone_number']);
        }

        if (empty($defaultFields['address'])) {
            unset($existingFields['address']);
        }

        foreach ($requiredIndexes as $index) {
            if (empty($existingFields[$index]) && !empty($defaultFields[$index])) {
                $existingFields[$index] = $defaultFields[$index];
            }
        }

        $paymentField = apply_filters('fluent_booking/payment_booking_field', [], $calendarSlot, $existingFields);

        if (!$paymentField) {
            unset($existingFields['payment_method']);
        } else {
            $existingFields['payment_method'] = $paymentField;
        }

        $existingFields['email']['disabled'] = false;

        $bookingFields = apply_filters('fluent_booking/booking_fields', array_values($existingFields), $calendarSlot);

        return $bookingFields;
    }

    public static function getBookingFieldLabels(CalendarSlot $calendarSlot, $enabledOnly = false)
    {
        $fields = self::getBookingFields($calendarSlot, true);

        $labels = [];
        foreach ($fields as $field) {
            if ($enabledOnly && !Arr::isTrue($field, 'enabled')) {
                continue;
            }

            $labels[$field['name']] = $field['label'];
        }

        return $labels;
    }

    public static function generateFieldName($calendarEvent, $fieldLabel)
    {
        $fieldLabel = preg_replace('/[^A-Za-z0-9]/', '_', $fieldLabel);
        $fieldName = 'custom_' . strtolower($fieldLabel);
        $bookingFields = self::getBookingFields($calendarEvent);
        
        $matched = 0;
        foreach ($bookingFields as $field) {
            if (strpos($field['name'], $fieldName) !== false) {
                $matched++;
            }
        }

        if ($matched) {
            $fieldName .= '_' . $matched;
        }
        return $fieldName;
    }

    public static function maybeGenerateFieldName($calendarEvent, $fieldValue)
    {
        $bookingFields = self::getBookingFields($calendarEvent);

        foreach ($bookingFields as $field) {
            if ($field['name'] == $fieldValue['name'] && $field['index'] != $fieldValue['index']) {
                return self::generateFieldName($calendarEvent, $fieldValue['label']);
            }
        }

        return sanitize_text_field($fieldValue['name']);
    }

    public static function getFormattedCustomBookingData(Booking $booking, $htmlSupport = true, $isPublic = false)
    {
        $customFormData = $booking->getMeta('custom_fields_data', []);
        if (!$customFormData) {
            return [];
        }

        $labels = self::getBookingFieldLabels($booking->calendar_event);

        $formattedData = [];

        foreach ($customFormData as $dataKey => $value) {
            $label = $labels[$dataKey] ?? $dataKey;

            $formattedValue = is_array($value) ? implode(', ', $value) : $value;

            $field = self::getBookingFieldByName($booking->calendar_event, $dataKey);

            $fieldType = Arr::get($field, 'type');

            if ($fieldType == 'file' && is_array($value)) {
                $formattedValue = self::getUploadedFiles($value, $htmlSupport);
            }

            if ($fieldType == 'hidden') {
                if ($isPublic) continue;
                $formattedValue = EditorShortcodeParser::parse($formattedValue, $booking);
            }

            $formattedData[$dataKey] = [
                'label' => $label,
                'type'  => $fieldType,
                'value' => $formattedValue
            ];
        }

        return $formattedData;
    }

    public static function getCustomFields($calendarEvent, $withConfig = false)
    {
        $existingFields = $calendarEvent->getMeta('booking_fields', []);

        if (!$existingFields) {
            return [];
        }

        $customFields = [];

        foreach ($existingFields as $existingField) {
            if (Arr::get($existingField, 'system_defined') || !Arr::isTrue($existingField, 'enabled')) {
                continue;
            }
            if ($withConfig) {
                $customFields[$existingField['name']] = $existingField;
            } else {
                $customFields[$existingField['name']] = $existingField['label'];
            }
        }

        return $customFields;
    }

    public static function getBookingFieldByName($calendarEvent, $name)
    {
        $fields = self::getBookingFields($calendarEvent, true);

        foreach ($fields as $field) {
            if (Arr::get($field, 'name') == $name) {
                return $field;
            }
        }

        return [];
    }

    public static function hasPhoneNumberField($fields)
    {
        if(!$fields) {
            return false;
        }

        foreach ($fields as $field) {
            if ($field['type'] == 'phone') {
                return true;
            } else if ($field['name'] == 'location') {
                if (!empty($field['options'])) {
                    foreach ($field['options'] as $option) {
                        if (Arr::get($option, 'type') == 'phone_guest') {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    public static function getUploadedFiles($fieldValue, $htmlSupport = true)
    {
        if (empty($fieldValue)) {
            return '';
        }

        $files = array_map(function($file) use ($htmlSupport) {
            if ($htmlSupport) {
                return '<a href="' . esc_url($file) . '" target="_blank" download="' . esc_attr(basename($file)) . '">' . esc_html(basename($file)) . '</a>';
            }
            return $file;
        }, $fieldValue);
    
        $separator = $htmlSupport ? '<br>' : PHP_EOL;

        return implode($separator, $files);
    }

    public static function validateDateFields($customFieldsData, $calendarEvent)
    {
        foreach ($customFieldsData as $fieldKey => $fieldValue) {
            $field = self::getBookingFieldByName($calendarEvent, $fieldKey);
            if ($fieldValue && Arr::get($field, 'type') == 'date') {
                $minDate = Arr::get($field, 'min_date');
                $maxDate = Arr::get($field, 'max_date');

                $fieldValue = DateTimeHelper::getFormattedDate($fieldValue, Arr::get($field, 'date_format'));
                $minDate = gmdate('Y-m-d', strtotime($minDate ?: '1900-01-01'));
                $maxDate = gmdate('Y-m-d', strtotime($maxDate ?: gmdate('Y-12-31')));

                if ($minDate && $fieldValue < $minDate) {
                    /* translators: %1$s: Field label, %2$s: Minimum date */
                    return new \WP_Error('invalid_date', sprintf(__('The date for %1$s cannot be earlier than %2$s.', 'fluent-booking'), $field['label'], $minDate));
                }
                if ($maxDate && $fieldValue > $maxDate) {
                    /* translators: %1$s: Field label, %2$s: Maximum date */
                    return new \WP_Error('invalid_date', sprintf(__('The date for %1$s cannot be later than %2$s.', 'fluent-booking'), $field['label'], $maxDate));
                }
            }
        }
        return true;
    }
}
