<?php
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber

/**
 * Reconcile all local service rows belonging to one Square booking.
 *
 * A Square booking can contain several sequential appointment segments while
 * Yatoon stores one row per primary service. This maps segment boundaries back
 * to those rows, includes intervening Design/Add-on segments in the preceding
 * service, and updates local start/end/staff values after edits made in Square.
 *
 * @param array $square_booking Square Booking API object.
 * @return int Number of local rows changed.
 */
function yatoon_reconcile_square_booking_segments( $square_booking ) {
    global $wpdb;

    $square_id = sanitize_text_field( (string) ( $square_booking['id'] ?? '' ) );
    $segments  = isset( $square_booking['appointment_segments'] ) && is_array( $square_booking['appointment_segments'] )
        ? array_values( $square_booking['appointment_segments'] )
        : array();
    if ( !$square_id || !$segments || empty( $square_booking['start_at'] ) ) return 0;

    $bookings_table = $wpdb->prefix . 'yatoon_bookings';
    $options_table  = $wpdb->prefix . 'yatoon_service_options';
    $links_table    = $wpdb->prefix . 'yatoon_booking_options';
    $services_table = $wpdb->prefix . 'yatoon_services';
    $staff_table    = $wpdb->prefix . 'yatoon_staff';

    $rows = yatoon_db_get_results( $wpdb->prepare(
        "SELECT id, service_id, staff_id, start_time, end_time, service_order
         FROM {$bookings_table}
         WHERE square_booking_id = %s
           AND status NOT IN ('cancelled','cancelled_by_customer','CANCELLED_BY_CUSTOMER','CANCELLED_BY_SELLER','DECLINED')
         ORDER BY service_order ASC, start_time ASC, id ASC",
        $square_id
    ) );
    if ( !$rows ) return 0;

    $row_maps = array();
    foreach ( $rows as $row ) {
        $option_rows = yatoon_db_get_results( $wpdb->prepare(
            "SELECT o.id, o.square_id, o.group_name
             FROM {$links_table} bo
             INNER JOIN {$options_table} o ON o.id = bo.option_id
             WHERE bo.booking_id = %d AND o.square_id IS NOT NULL AND o.square_id != ''",
            $row->id
        ) );
        $main_ids = array();
        foreach ( (array) $option_rows as $option_row ) {
            if ( (string) $option_row->group_name !== 'Add-on' ) $main_ids[] = (string) $option_row->square_id;
        }
        if ( !$main_ids ) {
            $service_square_id = yatoon_db_get_var( $wpdb->prepare(
                "SELECT square_id FROM {$services_table} WHERE id = %d LIMIT 1", $row->service_id
            ) );
            if ( $service_square_id ) $main_ids[] = (string) $service_square_id;
        }
        $row_maps[] = array( 'row' => $row, 'main_ids' => array_values( array_unique( $main_ids ) ) );
    }

    try {
        $cursor = new DateTime( $square_booking['start_at'] );
        $cursor->setTimezone( wp_timezone() );
    } catch ( Exception $e ) {
        return 0;
    }

    $seg_index = 0;
    $changed   = 0;
    $seg_count = count( $segments );
    foreach ( $row_maps as $row_index => $row_map ) {
        if ( $seg_index >= $seg_count ) break;

        $next_boundary = $seg_count;
        if ( isset( $row_maps[$row_index + 1] ) && $row_maps[$row_index + 1]['main_ids'] ) {
            for ( $probe = $seg_index + 1; $probe < $seg_count; $probe++ ) {
                $probe_var = (string) ( $segments[$probe]['service_variation_id'] ?? '' );
                if ( in_array( $probe_var, $row_maps[$row_index + 1]['main_ids'], true ) ) {
                    $next_boundary = $probe;
                    break;
                }
            }
        }
        if ( $row_index === count( $row_maps ) - 1 ) $next_boundary = $seg_count;
        if ( $next_boundary <= $seg_index ) $next_boundary = min( $seg_count, $seg_index + 1 );

        $row_start = clone $cursor;
        $duration  = 0;
        $used_vars = array();
        $first_seg = $segments[$seg_index];
        for ( ; $seg_index < $next_boundary; $seg_index++ ) {
            $duration += max( 0, intval( $segments[$seg_index]['duration_minutes'] ?? 0 ) );
            $var_id = (string) ( $segments[$seg_index]['service_variation_id'] ?? '' );
            if ( $var_id ) $used_vars[] = $var_id;
        }
        if ( $duration <= 0 ) $duration = max( 1, (int) round( ( strtotime( $row_map['row']->end_time ) - strtotime( $row_map['row']->start_time ) ) / 60 ) );
        $cursor->modify( '+' . $duration . ' minutes' );

        $update = array(
            'start_time' => $row_start->format( 'Y-m-d H:i:s' ),
            'end_time'   => $cursor->format( 'Y-m-d H:i:s' ),
            'updated_at' => current_time( 'mysql' ),
        );
        $team_member_id = (string) ( $first_seg['team_member_id'] ?? '' );
        if ( $team_member_id ) {
            $staff_id = yatoon_db_get_var( $wpdb->prepare( "SELECT id FROM {$staff_table} WHERE square_id = %s LIMIT 1", $team_member_id ) );
            if ( $staff_id ) $update['staff_id'] = intval( $staff_id );
        }

        if ( $update['start_time'] !== $row_map['row']->start_time
            || $update['end_time'] !== $row_map['row']->end_time
            || ( isset( $update['staff_id'] ) && intval( $update['staff_id'] ) !== intval( $row_map['row']->staff_id ) ) ) {
            yatoon_db_update( $bookings_table, $update, array( 'id' => $row_map['row']->id ) );
            $changed++;
        }

        // Reflect Square-added catalog segments in the local option links so the
        // service/design labels agree as well as the times.
        foreach ( array_unique( $used_vars ) as $used_var ) {
            $option_id = yatoon_db_get_var( $wpdb->prepare( "SELECT id FROM {$options_table} WHERE square_id = %s LIMIT 1", $used_var ) );
            if ( !$option_id ) continue;
            $exists = yatoon_db_get_var( $wpdb->prepare(
                "SELECT booking_id FROM {$links_table} WHERE booking_id = %d AND option_id = %d LIMIT 1",
                $row_map['row']->id, $option_id
            ) );
            if ( !$exists ) yatoon_db_insert( $links_table, array( 'booking_id' => $row_map['row']->id, 'option_id' => $option_id ) );
        }
    }

    return $changed;
}
/**
 * Shared runtime contract for every Yatoon Booking package.
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}

if ( !function_exists( 'yatoon_db_call' ) ) {
    function yatoon_db_call( $method, $args ) {
        global $wpdb;
        $allowed = array( 'get_var', 'get_row', 'get_results', 'get_col', 'query', 'insert', 'update', 'delete' );
        if ( !in_array( $method, $allowed, true ) ) {
            return null;
        }
        return call_user_func_array( array( $wpdb, $method ), $args );
    }
}

if ( !function_exists( 'yatoon_db_get_var' ) ) {
    function yatoon_db_get_var() { return yatoon_db_call( 'get_var', func_get_args() ); }
    function yatoon_db_get_row() { return yatoon_db_call( 'get_row', func_get_args() ); }
    function yatoon_db_get_results() { return yatoon_db_call( 'get_results', func_get_args() ); }
    function yatoon_db_get_col() { return yatoon_db_call( 'get_col', func_get_args() ); }
    function yatoon_db_query() { return yatoon_db_call( 'query', func_get_args() ); }
    function yatoon_db_insert() { return yatoon_db_call( 'insert', func_get_args() ); }
    function yatoon_db_update() { return yatoon_db_call( 'update', func_get_args() ); }
    function yatoon_db_delete() { return yatoon_db_call( 'delete', func_get_args() ); }
}

if ( !function_exists( 'yatoon_should_run_schema_migration' ) ) {
    function yatoon_should_run_schema_migration( $installed_version, $target_version ) {
        return !version_compare( (string) $installed_version, (string) $target_version, '>=' );
    }
}

if ( !function_exists( 'yatoon_record_onboarding_milestone' ) ) {
    function yatoon_record_onboarding_milestone( $milestone ) {
        $milestone = sanitize_key( $milestone );
        if ( '' === $milestone ) {
            return false;
        }
        $milestones = get_option( 'yatoon_onboarding_milestones', array() );
        if ( !is_array( $milestones ) ) {
            $milestones = array();
        }
        if ( isset( $milestones[ $milestone ] ) ) {
            return false;
        }
        $recorded_at = current_time( 'mysql' );
        $milestones[ $milestone ] = $recorded_at;
        update_option( 'yatoon_onboarding_milestones', $milestones, false );
        do_action( 'yatoon_onboarding_milestone_recorded', $milestone, $recorded_at );
        return true;
    }
}

if ( !function_exists( 'yatoon_track_created_booking_milestone' ) ) {
    function yatoon_track_created_booking_milestone( $booking_data ) {
        unset( $booking_data );
        $test_flag = filter_input( INPUT_POST, 'yatoon_test_booking', FILTER_SANITIZE_NUMBER_INT );
        $is_test = current_user_can( 'manage_options' )
            && '1' === get_option( 'yatoon_test_booking_mode', '0' )
            && '1' === (string) $test_flag;
        yatoon_record_onboarding_milestone( $is_test ? 'first_test_booking' : 'first_real_booking' );
    }
    add_action( 'yatoon_booking_created', 'yatoon_track_created_booking_milestone', 1, 1 );
}
