<?php

namespace Booktics\Order;

use Booktics\Models\Service_Model;
use Booktics\Models\Team_Member_Model;
use WP_Error;

class Order_Validator {
    /**
     * Validate order creation request
     *
     * @param array $data Order data
     *
     * @return true|WP_Error Returns true if valid, WP_Error otherwise
     */
    public function validate( array $data ) {
        $error = new WP_Error();

        // Validate basic required fields
        $required_fields = array(
            'items',
        );

        foreach ( $required_fields as $field ) {
            if ( empty( $data[ $field ] ) ) {
                /* translators: %s: Field name */
                $error->add( 'missing_field', sprintf( __( '%s is required', 'booktics' ), $field ) );
            }
        }

        if ( empty( $data['customer_id'] ) && empty( $data['customer']['email'] ) ) {
            $error->add( 'missing_field', __( 'Customer email is required', 'booktics' ) );
        }

        if ( empty( $data['items'] ) || ! is_array( $data['items'] ) ) {
            $error->add( 'invalid_items', __( 'Order must contain at least one item', 'booktics' ) );

            return $error;
        }

        foreach ( $data['items'] as $item ) {
            $item_validation = $this->validate_order_item( $item );
            if ( is_wp_error( $item_validation ) ) {
                return $item_validation;
            }
        }

        return $error->has_errors() ? $error : true;
    }

    /**
     * Validate individual order item
     *
     * @param array $item Order item data
     *
     * @return true|WP_Error Returns true if valid, WP_Error otherwise
     */
    private function validate_order_item( array $item ) {
        $error = new WP_Error();

        $service = ( new Service_Model() )->find( $item['service_id'] );
        if ( ! $service ) {
            $error->add( 'invalid_service', __( 'Invalid service selected', 'booktics' ) );
        }

        $team_member = ( new Team_Member_Model() )->find( $item['team_member_id'] );
        if ( ! $team_member ) {
            $error->add( 'invalid_team_member', __( 'Invalid team member selected', 'booktics' ) );
        }
        $error = apply_filters( 'booktics_extra_service_validate', $error, $item );

        return $error->has_errors() ? $error : true;
    }

    /**
     * Validate time slot availability
     *
     * @param array $item Order item data
     *
     * @return true|WP_Error Returns true if valid, WP_Error otherwise
     */
    private function validate_time_slot( array $item ) {
        $error = new WP_Error();

        $args = array(
            'post_type'      => 'booktics-appointment',
            'post_status'    => 'any',
            'posts_per_page' => 1,
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering appointments by meta fields
            'meta_query'     => array(
                'relation' => 'AND',
                array(
                    'key'     => 'date',
                    'value'   => $item['date'],
                    'compare' => '=',
                ),
                array(
                    'key'     => 'team_member_id',
                    'value'   => $item['team_member_id'],
                    'compare' => '=',
                ),
                array(
                    'relation' => 'OR',
                    // Appointment starts during requested time slot
                    array(
                        'relation' => 'AND',
                        array(
                            'key'     => 'start_time',
                            'value'   => $item['start_time'],
                            'compare' => '<=',
                        ),
                        array(
                            'key'     => 'end_time',
                            'value'   => $item['start_time'],
                            'compare' => '>',
                        ),
                    ),
                    // Appointment ends during requested time slot
                    array(
                        'relation' => 'AND',
                        array(
                            'key'     => 'start_time',
                            'value'   => $item['end_time'],
                            'compare' => '<',
                        ),
                        array(
                            'key'     => 'end_time',
                            'value'   => $item['end_time'],
                            'compare' => '>=',
                        ),
                    ),
                ),
            ),
        );

        $query = new \WP_Query( $args );

        if ( $query->have_posts() ) {
            $error->add(
                'time_slot_unavailable',
                sprintf(
                /* translators: 1: Start time, 2: End time, 3: Date */
                    __( 'Time slot %1$s - %2$s on %3$s is not available', 'booktics' ),
                    $item['start_time'],
                    $item['end_time'],
                    $item['date']
                )
            );
        }

        return $error->has_errors() ? $error : true;
    }
}
