<?php
namespace Bookaro\Controller\Rest;

defined( 'ABSPATH' ) || exit;

use Bookaro\Repository\BookingRepository;
use Bookaro\Service\ScheduleService;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

class ProviderBookingsRangeController extends BaseController
{
    private BookingRepository $db;
    private ScheduleService $schedule;

    public function __construct( BookingRepository $db, ScheduleService $schedule )
    {
        $this->db = $db;
        $this->schedule = $schedule;
    }

    public function register_routes(): void
    {
        register_rest_route( $this->namespace, '/provider/(?P<id>\d+)/bookings', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_bookings' ],
                'permission_callback' => [ $this, 'can_view_bookings' ],
                'args'                => [
                    'from' => [
                        'required'          => true,
                        'validate_callback' => fn( $v ) => preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) === 1,
                    ],
                    'to'   => [
                        'required'          => true,
                        'validate_callback' => fn( $v ) => preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) === 1,
                    ],
                ],
            ],
        ] );

        register_rest_route( $this->namespace, '/provider/exceptions/range', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'apply_exception_range' ],
                'permission_callback' => [ $this, 'can_manage_exceptions' ],
                'args'                => [
                    'from' => [
                        'required'          => true,
                        'validate_callback' => fn( $v ) => preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) === 1,
                    ],
                    'to'   => [
                        'required'          => true,
                        'validate_callback' => fn( $v ) => preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) === 1,
                    ],
                    'is_open' => [
                        'required' => false,
                        'default'  => 0,
                    ],
                ],
            ],
        ] );

        register_rest_route( $this->namespace, '/provider/exceptions/copy-week', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'copy_exception_week' ],
                'permission_callback' => [ $this, 'can_manage_exceptions' ],
                'args'                => [
                    'source' => [
                        'required'          => true,
                        'validate_callback' => fn( $v ) => preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) === 1,
                    ],
                    'target' => [
                        'required'          => true,
                        'validate_callback' => fn( $v ) => preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) === 1,
                    ],
                    'replace' => [
                        'required' => false,
                        'default'  => true,
                    ],
                ],
            ],
        ] );
    }

    public function can_view_bookings( WP_REST_Request $req )
    {
        // Bug 27: previously this gate used bookaro_user_has_dashboard_access(),
        // which passes for customers as well as providers. The follow-up
        // cross-user ID check was then wrapped in
        // `if ( bookaro_user_has_provider_access() && ! manage_options )`,
        // so a logged-in customer fell through both branches and could
        // request /provider/{any_id}/bookings. Lite's BookingRepository
        // returns [] from get_export_bookings, so no rows actually leaked
        // here — but the gate's intent (provider OR admin only) was broken,
        // and Pro's repo override would expose this immediately. Use the
        // tighter check; bookaro_user_has_provider_access() already returns
        // true for users with manage_options, so admins still pass.
        if ( ! bookaro_user_has_provider_access() ) {
            return new \WP_Error(
                'bookaro_forbidden',
                __( 'Permission denied.', 'mybookaro' ),
                [ 'status' => 403 ]
            );
        }

        $provider_id = (int) $req->get_param( 'id' );
        if ( $provider_id < 1 ) {
            return new \WP_Error(
                'bookaro_invalid_provider',
                __( 'Invalid provider.', 'mybookaro' ),
                [ 'status' => 400 ]
            );
        }

        // Non-admin providers can only query their OWN provider_id.
        if ( ! current_user_can( 'manage_options' ) && $provider_id !== get_current_user_id() ) {
            return new \WP_Error(
                'bookaro_forbidden',
                __( 'You do not have permission to access these bookings.', 'mybookaro' ),
                [ 'status' => 403 ]
            );
        }

        return true;
    }

    public function get_bookings( WP_REST_Request $req ): WP_REST_Response|\WP_Error
    {
        $provider_id = (int) $req->get_param( 'id' );
        $from        = (string) $req->get_param( 'from' );
        $to          = (string) $req->get_param( 'to' );

        // Bug 31: cap the requested range. See BaseController for the
        // rationale — every range REST endpoint shares the same limit.
        $range_check = $this->require_range_within_limit( $from, $to );
        if ( $range_check instanceof \WP_Error ) {
            return $range_check;
        }
        $resource_label_singular = function_exists( 'bookaro_get_resource_label_singular' )
            ? sanitize_text_field( (string) bookaro_get_resource_label_singular() )
            : __( 'Listing', 'mybookaro' );
        if ( '' === $resource_label_singular ) {
            $resource_label_singular = __( 'Listing', 'mybookaro' );
        }
        $resource_label_plural = function_exists( 'bookaro_get_resource_label_plural' )
            ? sanitize_text_field( (string) bookaro_get_resource_label_plural() )
            : __( 'Listings', 'mybookaro' );
        if ( '' === $resource_label_plural ) {
            $resource_label_plural = __( 'Listings', 'mybookaro' );
        }

        $rows = $this->db->get_export_bookings( $provider_id, $from, $to );
        $items = array_map(
            function ( array $row ) use ( $resource_label_singular ): array {
                $listing_id = isset( $row['listing_id'] ) ? (int) $row['listing_id'] : 0;
                $provider_name = sanitize_text_field( (string) ( $row['provider_name'] ?? '' ) );
                if ( '' === $provider_name ) {
                    $provider_id = isset( $row['provider_id'] ) ? (int) $row['provider_id'] : 0;
                    if ( $provider_id > 0 ) {
                        $provider = get_user_by( 'ID', $provider_id );
                        if ( $provider && isset( $provider->display_name ) ) {
                            $provider_name = sanitize_text_field( (string) $provider->display_name );
                        }
                    }
                }
                $listing_title = sanitize_text_field( (string) ( $row['listing_title'] ?? '' ) );
                if ( '' === $listing_title ) {
                    $listing_title = ( '' !== $provider_name ) ? $provider_name : $resource_label_singular;
                }
                $listing_url = '';
                if ( $listing_id > 0 ) {
                    $permalink = get_permalink( $listing_id );
                    $listing_url = is_string( $permalink ) ? $permalink : '';
                }
                return [
                    'id'               => isset( $row['id'] ) ? (int) $row['id'] : 0,
                    'service_label'    => (string) ( $row['service_label'] ?? '' ),
                    'booking_date'     => (string) ( $row['booking_date'] ?? '' ),
                    'booking_date_to'  => $row['booking_date_to'] ?? null,
                    'status'           => (string) ( $row['status'] ?? '' ),
                    'price'            => isset( $row['price'] ) ? (float) $row['price'] : 0.0,
                    'price_formatted'  => function_exists( 'bookaro_format_price' )
                        ? bookaro_format_price( $row['price'] ?? 0 )
                        : '',
                    'customer_name'    => (string) ( $row['customer_name'] ?? '' ),
                    'customer_email'   => (string) ( $row['customer_email'] ?? '' ),
                    'customer_phone'   => (string) ( $row['customer_phone'] ?? '' ),
                    'listing_id'       => $listing_id,
                    'listing_title'    => $listing_title,
                    'listing_url'      => $listing_url,
                ];
            },
            $rows
        );

        return rest_ensure_response( [
            'items' => $items,
            'resource_label_singular' => $resource_label_singular,
            'resource_label_plural' => $resource_label_plural,
        ] );
    }

    public function can_manage_exceptions( WP_REST_Request $req )
    {
        $auth = $this->require_authenticated_write(
            $req,
            __( 'You must be logged in to update availability.', 'mybookaro' )
        );
        if ( is_wp_error( $auth ) ) {
            return $auth;
        }

        if ( ! bookaro_user_has_provider_access() ) {
            return new \WP_Error(
                'bookaro_forbidden',
                __( 'Permission denied.', 'mybookaro' ),
                [ 'status' => 403 ]
            );
        }

        return true;
    }

    public function apply_exception_range( WP_REST_Request $req ): WP_REST_Response|\WP_Error
    {
        $provider_id = get_current_user_id();
        $from = sanitize_text_field( (string) $req->get_param( 'from' ) );
        $to = sanitize_text_field( (string) $req->get_param( 'to' ) );
        $is_open = (int) $req->get_param( 'is_open' );

        $result = $this->schedule->apply_exception_range( $provider_id, $from, $to, $is_open );
        if ( is_wp_error( $result ) ) {
            return $result;
        }

        return rest_ensure_response( [
            'success' => true,
            'count'   => (int) $result,
        ] );
    }

    public function copy_exception_week( WP_REST_Request $req ): WP_REST_Response|\WP_Error
    {
        $provider_id = get_current_user_id();
        $source = sanitize_text_field( (string) $req->get_param( 'source' ) );
        $target = sanitize_text_field( (string) $req->get_param( 'target' ) );
        $replace = (bool) $req->get_param( 'replace' );

        $result = $this->schedule->copy_exception_week( $provider_id, $source, $target, $replace );
        if ( is_wp_error( $result ) ) {
            return $result;
        }

        return rest_ensure_response( [
            'success' => true,
            'count'   => (int) $result,
        ] );
    }
}
