<?php
/**
 * Staff × location assignments, service eligibility, price overrides and hours.
 */
if ( ! defined( 'ABSPATH' ) ) { exit;
}

class YATOON_Staff_Locations {
    const SCHEMA = '4.4.3-staff-locations-v1';

    public static function init() {
        self::install_schema();
        add_action( 'admin_menu', array( __CLASS__, 'add_menu' ), 24 );
        add_action( 'admin_post_yatoon_save_staff_location_rule', array( __CLASS__, 'save_rule' ) );
        add_action( 'admin_post_yatoon_delete_staff_location_rule', array( __CLASS__, 'delete_rule' ) );
    }

    public static function install_schema() {
        if ( get_option( 'yatoon_staff_locations_schema', '' ) === self::SCHEMA ) { return;
        }
        global $wpdb;
        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        $charset = $wpdb->get_charset_collate();
        dbDelta( "CREATE TABLE {$wpdb->prefix}yatoon_staff_location_rules (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            staff_id bigint(20) NOT NULL,
            location_id bigint(20) NOT NULL,
            service_id bigint(20) NOT NULL DEFAULT 0,
            is_active tinyint(1) NOT NULL DEFAULT 1,
            price_override decimal(10,2) DEFAULT NULL,
            hours_json longtext DEFAULT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            updated_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY staff_location_service (staff_id,location_id,service_id),
            KEY location_service (location_id,service_id,is_active),
            KEY staff_active (staff_id,is_active)
        ) {$charset};" );
        if ( YATOON_Schema_Verifier::tables_exist( array( 'yatoon_staff_location_rules' ) ) ) {
            update_option( 'yatoon_staff_locations_schema', self::SCHEMA, false );
        }
    }

    public static function staff_has_rules( $staff_id ) {
        if ( class_exists( 'YATOON_Feature_Modules' ) && ! YATOON_Feature_Modules::enabled( 'staff_locations' ) ) { return false;
        }
        global $wpdb;
        static $cache = array();
        $staff_id = absint( $staff_id );
        if ( ! array_key_exists( $staff_id, $cache ) ) {
            $cache[ $staff_id ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$wpdb->prefix}yatoon_staff_location_rules WHERE staff_id=%d LIMIT 1", $staff_id ) );
        }
        return $cache[ $staff_id ];
    }

    public static function rule_for( $staff_id, $service_id, $location_id ) {
        global $wpdb;
        $staff_id = absint( $staff_id );
$service_id = absint( $service_id );
$location_id = absint( $location_id );
        if ( ! $staff_id || ! $location_id || ! self::staff_has_rules( $staff_id ) ) { return null;
        }
        return $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}yatoon_staff_location_rules
             WHERE staff_id=%d AND location_id=%d AND service_id IN (0,%d)
             ORDER BY service_id DESC LIMIT 1",
            $staff_id, $location_id, $service_id
        ) );
    }

    /** Legacy sites with no rule for a staff member remain unrestricted. */
    public static function is_assigned( $staff_id, $service_id, $location_id ) {
        if ( ! absint( $location_id ) || ! self::staff_has_rules( $staff_id ) ) { return true;
        }
        $rule = self::rule_for( $staff_id, $service_id, $location_id );
        return $rule && ! empty( $rule->is_active );
    }

    public static function allows( $staff_id, $service_id, $location_id, $start = null, $end = null ) {
        if ( ! self::is_assigned( $staff_id, $service_id, $location_id ) ) { return false;
        }
        $rule = self::rule_for( $staff_id, $service_id, $location_id );
        if ( ! $rule || ! $start || ! $end || empty( $rule->hours_json ) ) { return true;
        }
        $hours = json_decode( $rule->hours_json, true );
        if ( ! is_array( $hours ) ) { return true;
        }
        $day = strtolower( $start->format( 'D' ) );
        $day_rule = $hours[ $day ] ?? null;
        if ( ! is_array( $day_rule ) || empty( $day_rule['open'] ) ) { return false;
        }
        $start_hm = $start->format( 'H:i' );
$end_hm = $end->format( 'H:i' );
        if ( $start_hm < ( $day_rule['start'] ?? '00:00' ) || $end_hm > ( $day_rule['end'] ?? '23:59' ) ) { return false;
        }
        if ( ! empty( $day_rule['break_start'] ) && ! empty( $day_rule['break_end'] ) && $start_hm < $day_rule['break_end'] && $end_hm > $day_rule['break_start'] ) { return false;
        }
        return true;
    }

    public static function price_for( $staff_id, $service_id, $location_id, $fallback ) {
        $rule = self::rule_for( $staff_id, $service_id, $location_id );
        return $rule && null !== $rule->price_override ? max( 0, (float) $rule->price_override ) : (float) $fallback;
    }

    public static function filter_staff( array $staff, $service_id, $location_id ) {
        if ( ! absint( $location_id ) ) { return $staff;
        }
        return array_values( array_filter( $staff, function ( $member ) use ( $service_id, $location_id ) {
            return empty( $member->id ) || self::is_assigned( $member->id, $service_id, $location_id );
        } ) );
    }

    public static function filter_slots( array $slots, $staff_id, $service_id, $location_id, $duration, $date = '' ) {
        if ( ! absint( $staff_id ) || ! absint( $location_id ) ) { return $slots;
        }
        $tz = function_exists( 'yatoon_timezone' ) ? yatoon_timezone( $location_id ) : wp_timezone();
        return array_values( array_filter( $slots, function ( $slot ) use ( $staff_id, $service_id, $location_id, $duration, $date, $tz ) {
            $raw = $slot['start_at'] ?? ( $date && ! empty( $slot['time'] ) ? $date . ' ' . $slot['time'] : '' );
            if ( ! $raw ) { return true;
            }
            try {
                $start = new DateTime( $raw, $tz );
$end = clone $start;
$end->modify( '+' . max( 1, absint( $duration ) ) . ' minutes' );
                return self::allows( $staff_id, $service_id, $location_id, $start, $end );
            } catch ( Exception $e ) { return false; }
        } ) );
    }

    public static function add_menu() {
        add_submenu_page( 'yatoon-booking-system', __( 'Staff Locations', 'yatoon-booking-system' ), __( 'Staff Locations', 'yatoon-booking-system' ), 'yatoon_manage_staff', 'yatoon-staff-locations', array( __CLASS__, 'render_admin' ) );
    }

    private static function require_admin() {
        if ( ! current_user_can( 'yatoon_manage_staff' ) && ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to manage staff locations.', 'yatoon-booking-system' ) );
        }
    }

    private static function normalize_hours_from_post() {
        // phpcs:disable WordPress.Security.NonceVerification.Missing -- private helper is called only by save_rule() after check_admin_referer().
        $hours = array();
        foreach ( array( 'mon','tue','wed','thu','fri','sat','sun' ) as $day ) {
            $start = sanitize_text_field( wp_unslash( $_POST['hours'][ $day ]['start'] ?? '09:00' ) );
            $end = sanitize_text_field( wp_unslash( $_POST['hours'][ $day ]['end'] ?? '17:00' ) );
            $break_start = sanitize_text_field( wp_unslash( $_POST['hours'][ $day ]['break_start'] ?? '' ) );
            $break_end = sanitize_text_field( wp_unslash( $_POST['hours'][ $day ]['break_end'] ?? '' ) );
            foreach ( array( &$start, &$end, &$break_start, &$break_end ) as &$value ) { if ( $value && ! preg_match( '/^([01]\d|2[0-3]):[0-5]\d$/', $value ) ) { $value = '';
            }
            }
            $hours[ $day ] = array( 'open' => empty( $_POST['hours'][ $day ]['open'] ) ? 0 : 1, 'start' => $start ?: '09:00', 'end' => $end ?: '17:00', 'break_start' => $break_start, 'break_end' => $break_end );
        }
        // phpcs:enable WordPress.Security.NonceVerification.Missing
        return $hours;
    }

    public static function save_rule() {
        self::require_admin();
check_admin_referer( 'yatoon_save_staff_location_rule' );
global $wpdb;
        $id = absint( $_POST['rule_id'] ?? 0 );
        $price_raw = sanitize_text_field( wp_unslash( $_POST['price_override'] ?? '' ) );
        $data = array(
            'staff_id' => absint( $_POST['staff_id'] ?? 0 ),
            'location_id' => absint( $_POST['location_id'] ?? 0 ),
            'service_id' => absint( $_POST['service_id'] ?? 0 ),
            'is_active' => empty( $_POST['is_active'] ) ? 0 : 1,
            'price_override' => '' === $price_raw ? null : max( 0, (float) $price_raw ),
            'hours_json' => wp_json_encode( self::normalize_hours_from_post() ),
            'updated_at' => current_time( 'mysql' ),
        );
        if ( $data['staff_id'] && $data['location_id'] ) {
            if ( $id ) { $wpdb->update( $wpdb->prefix . 'yatoon_staff_location_rules', $data, array( 'id' => $id ) );
            } else { $data['created_at'] = current_time( 'mysql' );
$wpdb->replace( $wpdb->prefix . 'yatoon_staff_location_rules', $data ); }
        }
        wp_safe_redirect( admin_url( 'admin.php?page=yatoon-staff-locations' ) );
exit;
    }

    public static function delete_rule() {
        self::require_admin();
check_admin_referer( 'yatoon_delete_staff_location_rule' );
global $wpdb;
        $wpdb->delete( $wpdb->prefix . 'yatoon_staff_location_rules', array( 'id' => absint( $_GET['rule_id'] ?? 0 ) ) );
        wp_safe_redirect( admin_url( 'admin.php?page=yatoon-staff-locations' ) );
exit;
    }

    public static function render_admin() {
        self::require_admin();
global $wpdb;
        $edit_id = absint( $_GET['rule_id'] ?? 0 );
        $rule = $edit_id ? $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}yatoon_staff_location_rules WHERE id=%d", $edit_id ) ) : null;
        $hours = $rule ? json_decode( $rule->hours_json, true ) : YATOON_Business_Hours::get_default_hours();
        $staff = $wpdb->get_results( "SELECT id,name FROM {$wpdb->prefix}yatoon_staff WHERE is_active=1 ORDER BY name" );
        $locations = $wpdb->get_results( "SELECT id,name FROM {$wpdb->prefix}yatoon_locations WHERE is_active=1 ORDER BY name" );
        $services = $wpdb->get_results( "SELECT id,name FROM {$wpdb->prefix}yatoon_services WHERE is_active=1 ORDER BY name" );
        $rules = $wpdb->get_results( "SELECT r.*,st.name staff_name,l.name location_name,s.name service_name FROM {$wpdb->prefix}yatoon_staff_location_rules r JOIN {$wpdb->prefix}yatoon_staff st ON st.id=r.staff_id JOIN {$wpdb->prefix}yatoon_locations l ON l.id=r.location_id LEFT JOIN {$wpdb->prefix}yatoon_services s ON s.id=r.service_id ORDER BY st.name,l.name,s.name" );
        ?>
        <div class="wrap ysl-wrap"><h1><?php esc_html_e( 'Staff × Location Rules', 'yatoon-booking-system' ); ?></h1><p><?php esc_html_e( 'Once a staff member has at least one rule, only active matching locations and services are bookable for that staff member. Staff with no rules keep legacy unrestricted behavior.', 'yatoon-booking-system' ); ?></p>
        <div class="ysl-grid"><section class="ysl-panel"><h2><?php echo $rule ? esc_html__( 'Edit rule', 'yatoon-booking-system' ) : esc_html__( 'Add rule', 'yatoon-booking-system' ); ?></h2><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"><?php wp_nonce_field( 'yatoon_save_staff_location_rule' ); ?><input type="hidden" name="action" value="yatoon_save_staff_location_rule"><input type="hidden" name="rule_id" value="<?php echo esc_attr( $edit_id ); ?>">
        <label><?php esc_html_e( 'Staff', 'yatoon-booking-system' ); ?><select name="staff_id" required><option value=""><?php esc_html_e( 'Select', 'yatoon-booking-system' ); ?></option><?php foreach ( $staff as $item ) : ?><option value="<?php echo esc_attr( $item->id ); ?>" <?php selected( $rule->staff_id ?? 0, $item->id ); ?>><?php echo esc_html( $item->name ); ?></option><?php endforeach; ?></select></label>
        <label><?php esc_html_e( 'Location', 'yatoon-booking-system' ); ?><select name="location_id" required><option value=""><?php esc_html_e( 'Select', 'yatoon-booking-system' ); ?></option><?php foreach ( $locations as $item ) : ?><option value="<?php echo esc_attr( $item->id ); ?>" <?php selected( $rule->location_id ?? 0, $item->id ); ?>><?php echo esc_html( $item->name ); ?></option><?php endforeach; ?></select></label>
        <label><?php esc_html_e( 'Service', 'yatoon-booking-system' ); ?><select name="service_id"><option value="0"><?php esc_html_e( 'All services', 'yatoon-booking-system' ); ?></option><?php foreach ( $services as $item ) : ?><option value="<?php echo esc_attr( $item->id ); ?>" <?php selected( $rule->service_id ?? 0, $item->id ); ?>><?php echo esc_html( $item->name ); ?></option><?php endforeach; ?></select></label>
        <label><?php esc_html_e( 'Price override (blank = service price)', 'yatoon-booking-system' ); ?><input type="number" min="0" step="0.01" name="price_override" value="<?php echo esc_attr( isset( $rule->price_override ) ? $rule->price_override : '' ); ?>"></label><label><input type="checkbox" name="is_active" value="1" <?php checked( ! $rule || $rule->is_active ); ?>> <?php esc_html_e( 'Active', 'yatoon-booking-system' ); ?></label>
        <h3><?php esc_html_e( 'Weekly hours', 'yatoon-booking-system' ); ?></h3><table class="widefat"><thead><tr><th><?php esc_html_e( 'Day', 'yatoon-booking-system' ); ?></th><th><?php esc_html_e( 'Open', 'yatoon-booking-system' ); ?></th><th><?php esc_html_e( 'Start', 'yatoon-booking-system' ); ?></th><th><?php esc_html_e( 'End', 'yatoon-booking-system' ); ?></th><th><?php esc_html_e( 'Break', 'yatoon-booking-system' ); ?></th></tr></thead><tbody><?php foreach ( array( 'mon','tue','wed','thu','fri','sat','sun' ) as $day ) : $h = $hours[ $day ] ?? array(); ?><tr><td><?php echo esc_html( ucfirst( $day ) ); ?></td><td><input type="checkbox" name="hours[<?php echo esc_attr( $day ); ?>][open]" value="1" <?php checked( ! empty( $h['open'] ) ); ?>></td><td><input type="time" name="hours[<?php echo esc_attr( $day ); ?>][start]" value="<?php echo esc_attr( $h['start'] ?? '09:00' ); ?>"></td><td><input type="time" name="hours[<?php echo esc_attr( $day ); ?>][end]" value="<?php echo esc_attr( $h['end'] ?? '17:00' ); ?>"></td><td><input type="time" name="hours[<?php echo esc_attr( $day ); ?>][break_start]" value="<?php echo esc_attr( $h['break_start'] ?? '' ); ?>">–<input type="time" name="hours[<?php echo esc_attr( $day ); ?>][break_end]" value="<?php echo esc_attr( $h['break_end'] ?? '' ); ?>"></td></tr><?php endforeach; ?></tbody></table><p><button class="button button-primary"><?php esc_html_e( 'Save rule', 'yatoon-booking-system' ); ?></button></p></form></section>
        <section class="ysl-panel"><h2><?php esc_html_e( 'Rules', 'yatoon-booking-system' ); ?></h2><?php foreach ( $rules as $item ) : ?><article><div><strong><?php echo esc_html( $item->staff_name ); ?></strong><span><?php echo esc_html( $item->location_name . ' · ' . ( $item->service_name ?: __( 'All services', 'yatoon-booking-system' ) ) ); ?></span></div><div><a class="button button-small" href="<?php echo esc_url( admin_url( 'admin.php?page=yatoon-staff-locations&rule_id=' . $item->id ) ); ?>"><?php esc_html_e( 'Edit', 'yatoon-booking-system' ); ?></a> <a class="button button-small" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=yatoon_delete_staff_location_rule&rule_id=' . $item->id ), 'yatoon_delete_staff_location_rule' ) ); ?>"><?php esc_html_e( 'Delete', 'yatoon-booking-system' ); ?></a></div></article><?php endforeach; ?></section></div>
        <style>.ysl-wrap{max-width:1400px}.ysl-grid{display:grid;grid-template-columns:minmax(620px,1.2fr) minmax(320px,.8fr);gap:18px}.ysl-panel{background:#fff;border:1px solid #dcdcde;padding:20px}.ysl-panel>label{display:block;margin:12px 0;font-weight:600}.ysl-panel>form>label select,.ysl-panel>form>label input[type=number]{display:block;width:100%;margin-top:5px}.ysl-panel td input[type=time]{max-width:112px}.ysl-panel article{display:flex;justify-content:space-between;gap:12px;padding:12px 0;border-bottom:1px solid #eee}.ysl-panel article span{display:block;color:#646970}@media(max-width:1000px){.ysl-grid{grid-template-columns:1fr}}</style></div><?php
    }
}
