<?php

namespace Bookaro\Controller\Ajax;


defined( 'ABSPATH' ) || exit;

use Bookaro\Controller\AbstractController;
use Bookaro\Service\ScheduleService;
use Bookaro\Repository\BookingRepository;

/**
 * AJAX endpoints for provider scheduling settings.
 * Handles fetching and saving of availability, timeslots,
 * exceptions and email templates for the current provider.
 */
class ProviderSettingsController extends AbstractController
{
    private ScheduleService $schedule;

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

    public function register_hooks(): void
    {
        add_action( 'wp_ajax_bookaro_get_settings', [ $this, 'get_settings' ] );
        add_action( 'wp_ajax_bookaro_save_settings', [ $this, 'save_settings' ] );
        add_action( 'wp_ajax_bookaro_viewed_exceptions', [ $this, 'mark_exceptions_viewed' ] );
    }

    /**
     * Fetch provider settings (availability, exceptions, email templates).
     */
    public function get_settings(): void
    {
        check_ajax_referer( 'bookaro_nonce', 'security' );
        if ( ! is_user_logged_in() ) {
            wp_send_json_error( __( 'You must be logged in to view settings.', 'mybookaro' ) );
        }
        if ( ! bookaro_user_has_provider_access() ) {
            wp_send_json_error( __( 'You do not have permission to view provider settings.', 'mybookaro' ) );
        }

        $provider_id = get_current_user_id();

        $payload = $this->schedule->get_provider_settings_payload( $provider_id );

        wp_send_json_success( [
            'availability'    => $payload['availability'],
            'exceptions'      => $payload['exceptions'],
            'schedule_meta'   => $payload['schedule_meta'],
        ] );
    }

    /**
     * Save provider settings from the dashboard.
     */
    public function save_settings(): void
    {
        check_ajax_referer( 'bookaro_nonce', 'security' );
        if ( ! is_user_logged_in() ) {
            wp_send_json_error( __( 'You must be logged in to save settings.', 'mybookaro' ) );
        }
        if ( ! bookaro_user_has_provider_access() ) {
            wp_send_json_error( __( 'You do not have permission to update provider settings.', 'mybookaro' ) );
        }

        $provider_id = get_current_user_id();

        $availability_raw = sanitize_textarea_field( wp_unslash( $_POST['availability'] ?? '' ) );
        $exceptions_raw   = sanitize_textarea_field( wp_unslash( $_POST['exceptions'] ?? '' ) );
        $availability = json_decode( $availability_raw, true );
        $exceptions   = json_decode( $exceptions_raw, true );
        $normalized   = $this->schedule->normalize_availability_payload(
            is_array( $availability ) ? $availability : []
        );
        $normalized_exceptions = $this->schedule->normalize_exceptions_payload(
            is_array( $exceptions ) ? $exceptions : []
        );

        // Bug 61 (AJAX twin of REST fix): detect existing pending/approved
        // bookings on the dates the provider is about to close. The Vue UI
        // wires this AJAX path (not the REST endpoint patched earlier), so
        // we need to ship the same conflict list here or the warning banner
        // never appears in the Settings → Exceptions tab.
        $exception_conflicts = $this->collect_exception_conflicts(
            $provider_id,
            $normalized_exceptions
        );

        $this->schedule->set_weekly_availability( $provider_id, $normalized['weekly'] );
        $this->schedule->set_timeslots( $provider_id, $normalized['timeslots'] );
        $this->schedule->set_slots_per_interval( $provider_id, $normalized['slots_per_interval'] );
        $this->schedule->set_exceptions( $provider_id, $normalized_exceptions );

        wp_send_json_success( [
            'success'             => true,
            'exception_conflicts' => $exception_conflicts,
        ] );
    }

    /**
     * @param array<string,int> $normalized_exceptions Dates already normalized to Y-m-d => is_open.
     * @return array<int,array<string,mixed>>
     */
    private function collect_exception_conflicts( int $provider_id, array $normalized_exceptions ): array
    {
        $closed_dates = [];
        foreach ( $normalized_exceptions as $iso => $is_open ) {
            if ( (int) $is_open === 0 && preg_match( '/^\d{4}-\d{2}-\d{2}$/', (string) $iso ) === 1 ) {
                $closed_dates[ $iso ] = true;
            }
        }
        if ( empty( $closed_dates ) ) {
            return [];
        }

        global $wpdb;
        $repo = new BookingRepository();
        $table = esc_sql( $repo->get_table_name() );
        $dates_list = array_keys( $closed_dates );
        $placeholders = implode( ',', array_fill( 0, count( $dates_list ), '%s' ) );
        $params = array_merge( [ $provider_id ], $dates_list, $dates_list );
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $sql = "SELECT id, booking_date, booking_date_to, status, service_label
                FROM `{$table}`
                WHERE provider_id = %d
                  AND status IN ('pending','approved')
                  AND (
                      DATE(booking_date) IN ($placeholders)
                      OR DATE(booking_date_to) IN ($placeholders)
                  )";
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- table name is esc_sql()'d, values are bound via $wpdb->prepare().
        $rows = $wpdb->get_results( $wpdb->prepare( $sql, $params ), ARRAY_A );

        $conflicts = [];
        foreach ( (array) $rows as $row ) {
            $start_date = substr( (string) ( $row['booking_date'] ?? '' ), 0, 10 );
            $end_date   = (string) ( $row['booking_date_to'] ?? '' ) !== ''
                ? substr( (string) $row['booking_date_to'], 0, 10 )
                : $start_date;
            $hits = [];
            foreach ( $dates_list as $iso ) {
                if ( $iso >= $start_date && $iso <= $end_date ) {
                    $hits[] = $iso;
                }
            }
            $conflicts[] = [
                'id'              => (int) $row['id'],
                'service_label'   => (string) ( $row['service_label'] ?? '' ),
                'status'          => (string) ( $row['status'] ?? '' ),
                'booking_date'    => (string) $row['booking_date'],
                'booking_date_to' => (string) $row['booking_date_to'],
                'closed_dates'    => $hits,
            ];
        }
        return $conflicts;
    }

    /**
     * Mark the exceptions tab as viewed for the current user.
     */
    public function mark_exceptions_viewed(): void
    {
        check_ajax_referer( 'bookaro_nonce', 'security' );
        if ( ! is_user_logged_in() ) {
            wp_send_json_error( __( 'You must be logged in to update settings.', 'mybookaro' ) );
        }
        if ( ! bookaro_user_has_provider_access() ) {
            wp_send_json_error( __( 'You do not have permission to update settings.', 'mybookaro' ) );
        }

        update_user_meta( get_current_user_id(), 'bookaro_viewed_exceptions', 1 );
        wp_send_json_success( [ 'success' => true ] );
    }

    private function resolve_provider_id( int $listing_id ): int
    {
        if ( $listing_id < 1 ) {
            return 0;
        }
        if ( function_exists( 'bookaro_get_listing_owner_id' ) ) {
            return (int) bookaro_get_listing_owner_id( $listing_id );
        }
        $post = get_post( $listing_id );
        return $post ? (int) $post->post_author : 0;
    }
}
