<?php
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange
/**
 * Daily operations, reliability, finance ledger, and lightweight workflows.
 */
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class YATOON_Operations {
    const WORKFLOWS_OPTION = 'yatoon_workflows_v1';
    const HEALTH_OPTION = 'yatoon_health_snapshot_v1';

    public static function init() {
        self::install_schema();
        add_action( 'admin_menu', array( __CLASS__, 'add_menu' ), 22 );
        add_action( 'admin_post_yatoon_save_finance_settings', array( __CLASS__, 'save_finance_settings' ) );
        add_action( 'admin_post_yatoon_add_ledger_entry', array( __CLASS__, 'add_ledger_entry' ) );
        add_action( 'admin_post_yatoon_save_workflow', array( __CLASS__, 'save_workflow' ) );
        add_action( 'admin_post_yatoon_delete_workflow', array( __CLASS__, 'delete_workflow' ) );
        add_action( 'admin_post_yatoon_run_health_job', array( __CLASS__, 'run_health_job' ) );
        add_action( 'admin_post_yatoon_export_ledger', array( __CLASS__, 'export_ledger' ) );
        add_action( 'admin_post_yatoon_print_invoice', array( __CLASS__, 'print_invoice' ) );
        add_action( 'wp_ajax_yatoon_bulk_update_booking_status', array( __CLASS__, 'bulk_update_booking_status' ) );
        add_action( 'yatoon_booking_created', array( __CLASS__, 'booking_created' ), 80, 1 );
        add_action( 'yatoon_booking_status_changed', array( __CLASS__, 'booking_status_changed' ), 10, 3 );
        add_action( 'yatoon_payment_status_changed', array( __CLASS__, 'payment_status_changed' ), 10, 4 );
        add_action( 'yatoon_daily_health_snapshot', array( __CLASS__, 'capture_health_snapshot' ) );
        if ( ! wp_next_scheduled( 'yatoon_daily_health_snapshot' ) ) {
            wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'yatoon_daily_health_snapshot' );
        }
        if ( defined( 'WP_CLI' ) && WP_CLI ) {
            \WP_CLI::add_command( 'yatoon smoke-test', array( __CLASS__, 'cli_smoke_test' ) );
        }
    }

    public static function install_schema() {
        if ( YATOON_DB_VERSION === get_option( 'yatoon_operations_schema_version', '' ) ) {
            return;
        }
        global $wpdb;
        $table = $wpdb->prefix . 'yatoon_finance_ledger';
        $exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
        if ( $exists === $table ) {
            update_option( 'yatoon_operations_schema_version', YATOON_DB_VERSION, false );
            return;
        }
        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        $charset = $wpdb->get_charset_collate();
        dbDelta( "CREATE TABLE {$table} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            booking_id bigint(20) DEFAULT NULL,
            entry_type varchar(30) NOT NULL,
            amount decimal(10,2) NOT NULL DEFAULT 0,
            method varchar(40) DEFAULT '',
            reference varchar(255) DEFAULT '',
            note text DEFAULT NULL,
            created_by bigint(20) DEFAULT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY booking_id (booking_id),
            KEY entry_type (entry_type),
            KEY created_at (created_at)
        ) {$charset};" );
        if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table ) {
            update_option( 'yatoon_operations_schema_version', YATOON_DB_VERSION, false );
        }
    }

    public static function add_menu() {
        add_submenu_page(
            'yatoon-booking-system',
            __( 'Operations', 'yatoon-booking-system' ),
            __( 'Operations', 'yatoon-booking-system' ),
            'yatoon_manage_bookings',
            'yatoon-operations',
            array( __CLASS__, 'render_page' )
        );
    }

    private static function require_admin() {
        if ( ! current_user_can( 'yatoon_manage_bookings' ) ) {
            wp_die( esc_html__( 'You do not have permission to manage Yatoon operations.', 'yatoon-booking-system' ) );
        }
    }

    private static function redirect( $tab, $notice = 'saved' ) {
        wp_safe_redirect( add_query_arg(
            array( 'page' => 'yatoon-operations', 'tab' => sanitize_key( $tab ), 'yatoon_notice' => sanitize_key( $notice ) ),
            admin_url( 'admin.php' )
        ) );
        exit;
    }

    public static function save_finance_settings() {
        self::require_admin();
        check_admin_referer( 'yatoon_finance_settings' );
        update_option( 'yatoon_default_tax_rate', min( 100, max( 0, (float) ( $_POST['tax_rate'] ?? 0 ) ) ) );
        update_option( 'yatoon_default_service_fee', max( 0, (float) ( $_POST['service_fee'] ?? 0 ) ) );
        update_option( 'yatoon_invoice_prefix', sanitize_text_field( wp_unslash( $_POST['invoice_prefix'] ?? 'YTN' ) ) );
        self::redirect( 'finance' );
    }

    public static function add_ledger_entry() {
        self::require_admin();
        check_admin_referer( 'yatoon_add_ledger_entry' );
        $booking_id = absint( $_POST['booking_id'] ?? 0 );
        $type = sanitize_key( wp_unslash( $_POST['entry_type'] ?? '' ) );
        $allowed = array( 'payment', 'deposit', 'refund', 'adjustment', 'fee' );
        if ( ! in_array( $type, $allowed, true ) ) {
            self::redirect( 'finance', 'invalid' );
        }
        $amount = (float) ( $_POST['amount'] ?? 0 );
        if ( 'refund' === $type ) {
            $amount = -abs( $amount );
        }
        self::record_ledger(
            $booking_id,
            $type,
            $amount,
            sanitize_key( wp_unslash( $_POST['method'] ?? 'manual' ) ),
            sanitize_text_field( wp_unslash( $_POST['reference'] ?? '' ) ),
            sanitize_textarea_field( wp_unslash( $_POST['note'] ?? '' ) )
        );
        if ( $booking_id && 'refund' === $type ) {
            global $wpdb;
            $wpdb->update(
                $wpdb->prefix . 'yatoon_bookings',
                array( 'payment_status' => 'refunded', 'payment_updated_at' => current_time( 'mysql' ) ),
                array( 'id' => $booking_id ),
                array( '%s', '%s' ),
                array( '%d' )
            );
        }
        self::redirect( 'finance' );
    }

    public static function record_ledger( $booking_id, $type, $amount, $method = '', $reference = '', $note = '' ) {
        global $wpdb;
        return $wpdb->insert(
            $wpdb->prefix . 'yatoon_finance_ledger',
            array(
                'booking_id' => $booking_id ?: null,
                'entry_type' => sanitize_key( $type ),
                'amount' => round( (float) $amount, 2 ),
                'method' => sanitize_key( $method ),
                'reference' => sanitize_text_field( $reference ),
                'note' => sanitize_textarea_field( $note ),
                'created_by' => get_current_user_id() ?: null,
                'created_at' => current_time( 'mysql' ),
            ),
            array( '%d', '%s', '%f', '%s', '%s', '%s', '%d', '%s' )
        );
    }

    public static function save_workflow() {
        self::require_admin();
        check_admin_referer( 'yatoon_save_workflow' );
        $event = sanitize_key( wp_unslash( $_POST['event'] ?? '' ) );
        $action = sanitize_key( wp_unslash( $_POST['workflow_action'] ?? '' ) );
        if ( ! in_array( $event, array( 'booking_created', 'booking_status', 'payment_status' ), true )
            || ! in_array( $action, array( 'email_admin', 'email_customer', 'webhook', 'internal_note' ), true ) ) {
            self::redirect( 'automation', 'invalid' );
        }
        $rows = get_option( self::WORKFLOWS_OPTION, array() );
        $rows = is_array( $rows ) ? $rows : array();
        $rows[] = array(
            'id' => wp_generate_uuid4(),
            'name' => sanitize_text_field( wp_unslash( $_POST['name'] ?? 'Workflow' ) ),
            'event' => $event,
            'condition' => sanitize_key( wp_unslash( $_POST['condition'] ?? '' ) ),
            'action' => $action,
            'target' => sanitize_text_field( wp_unslash( $_POST['target'] ?? '' ) ),
            'subject' => sanitize_text_field( wp_unslash( $_POST['subject'] ?? 'Booking update' ) ),
            'message' => sanitize_textarea_field( wp_unslash( $_POST['message'] ?? '' ) ),
            'delay_minutes' => min( 43200, absint( $_POST['delay_minutes'] ?? 0 ) ),
            'enabled' => 1,
        );
        update_option( self::WORKFLOWS_OPTION, array_values( $rows ), false );
        self::redirect( 'automation' );
    }

    public static function delete_workflow() {
        self::require_admin();
        check_admin_referer( 'yatoon_delete_workflow' );
        $id = sanitize_text_field( wp_unslash( $_GET['workflow_id'] ?? '' ) );
        $rows = array_filter( (array) get_option( self::WORKFLOWS_OPTION, array() ), function( $row ) use ( $id ) {
            return ( $row['id'] ?? '' ) !== $id;
        } );
        update_option( self::WORKFLOWS_OPTION, array_values( $rows ), false );
        self::redirect( 'automation' );
    }

    public static function booking_created( $booking ) {
        $booking_id = absint( $booking['booking_id'] ?? $booking['id'] ?? 0 );
        self::run_workflows( 'booking_created', '', $booking_id );
    }

    public static function booking_status_changed( $booking_id, $new_status, $old_status = '' ) {
        unset( $old_status );
        self::run_workflows( 'booking_status', sanitize_key( $new_status ), absint( $booking_id ) );
    }

    public static function payment_status_changed( $booking_id, $new_status, $old_status = '', $note = '' ) {
        if ( $new_status === $old_status ) {
            return;
        }
        global $wpdb;
        $booking = $wpdb->get_row( $wpdb->prepare(
            "SELECT total_price, deposit_amount FROM {$wpdb->prefix}yatoon_bookings WHERE id = %d",
            $booking_id
        ) );
        if ( $booking && in_array( $new_status, array( 'paid_square_pos', 'deposit_paid', 'refunded' ), true ) ) {
            $type = 'refunded' === $new_status ? 'refund' : ( 'deposit_paid' === $new_status ? 'deposit' : 'payment' );
            $amount = 'deposit' === $type && (float) $booking->deposit_amount > 0
                ? (float) $booking->deposit_amount
                : (float) $booking->total_price;
            if ( 'refund' === $type ) {
                $amount *= -1;
            }
            self::record_ledger( $booking_id, $type, $amount, 'status_update', '', $note );
        }
        self::run_workflows( 'payment_status', sanitize_key( $new_status ), absint( $booking_id ) );
    }

    private static function run_workflows( $event, $condition, $booking_id ) {
        foreach ( (array) get_option( self::WORKFLOWS_OPTION, array() ) as $workflow ) {
            if ( empty( $workflow['enabled'] ) || ( $workflow['event'] ?? '' ) !== $event ) {
                continue;
            }
            if ( ! empty( $workflow['condition'] ) && $workflow['condition'] !== $condition ) {
                continue;
            }
            if ( class_exists( 'YATOON_Job_Queue' ) ) {
                YATOON_Job_Queue::enqueue(
                    'workflow_action',
                    array(
                        'workflow_id' => $workflow['id'] ?? '',
                        'event' => $event,
                        'condition' => $condition,
                        'booking_id' => absint( $booking_id ),
                    ),
                    absint( $workflow['delay_minutes'] ?? 0 ) * MINUTE_IN_SECONDS
                );
            }
        }
    }

    public static function execute_workflow_job( array $payload ) {
        $workflow_id = sanitize_text_field( $payload['workflow_id'] ?? '' );
        $workflow = null;
        foreach ( (array) get_option( self::WORKFLOWS_OPTION, array() ) as $candidate ) {
            if ( ( $candidate['id'] ?? '' ) === $workflow_id ) {
                $workflow = $candidate;
                break;
            }
        }
        if ( ! $workflow || empty( $workflow['enabled'] ) ) {
            return;
        }
        $event = sanitize_key( $payload['event'] ?? '' );
        $condition = sanitize_key( $payload['condition'] ?? '' );
        $booking_id = absint( $payload['booking_id'] ?? 0 );
        global $wpdb;
        $booking = $booking_id ? $wpdb->get_row( $wpdb->prepare(
            "SELECT b.*, s.name service_name, st.name staff_name
             FROM {$wpdb->prefix}yatoon_bookings b
             LEFT JOIN {$wpdb->prefix}yatoon_services s ON s.id=b.service_id
             LEFT JOIN {$wpdb->prefix}yatoon_staff st ON st.id=b.staff_id
             WHERE b.id=%d",
            $booking_id
        ), ARRAY_A ) : array();
        $replace = array(
            '{{booking_id}}' => (string) $booking_id,
            '{{customer_name}}' => (string) ( $booking['customer_name'] ?? '' ),
            '{{service}}' => (string) ( $booking['service_name'] ?? '' ),
            '{{staff}}' => (string) ( $booking['staff_name'] ?? '' ),
            '{{status}}' => (string) $condition,
            '{{start_time}}' => (string) ( $booking['start_time'] ?? '' ),
            '{{total}}' => number_format( (float) ( $booking['total_price'] ?? 0 ), 2 ),
        );
        $subject = strtr( (string) ( $workflow['subject'] ?? '' ), $replace );
        $message = strtr( (string) ( $workflow['message'] ?? '' ), $replace );
        if ( 'email_admin' === $workflow['action'] ) {
            if ( ! wp_mail( get_option( 'admin_email' ), $subject, $message ) ) {
                throw new RuntimeException( 'Administrator email could not be queued.' );
            }
        } elseif ( 'email_customer' === $workflow['action'] && ! empty( $booking['customer_email'] ) ) {
            if ( ! wp_mail( $booking['customer_email'], $subject, $message ) ) {
                throw new RuntimeException( 'Customer email could not be queued.' );
            }
        } elseif ( 'webhook' === $workflow['action'] && ! empty( $workflow['target'] ) ) {
            $response = wp_remote_post( esc_url_raw( $workflow['target'] ), array(
                'timeout' => 8,
                'headers' => array( 'Content-Type' => 'application/json' ),
                'body' => wp_json_encode( array( 'event' => $event, 'condition' => $condition, 'booking' => $booking ) ),
            ) );
            if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) >= 400 ) {
                throw new RuntimeException( 'Webhook delivery failed.' );
            }
        } elseif ( 'internal_note' === $workflow['action'] && $booking_id ) {
            $existing = trim( (string) ( $booking['notes'] ?? '' ) );
            $wpdb->update(
                $wpdb->prefix . 'yatoon_bookings',
                array( 'notes' => trim( $existing . "\n" . $message ) ),
                array( 'id' => $booking_id ),
                array( '%s' ),
                array( '%d' )
            );
        }
        YATOON_Activity_Log::record( 'workflow_run', 'Automation completed: ' . ( $workflow['name'] ?? 'Workflow' ), array( 'booking_id' => $booking_id ) );
    }

    public static function health_checks() {
        global $wpdb;
        $checks = array();
        $add = function( $key, $label, $ok, $detail ) use ( &$checks ) {
            $checks[] = compact( 'key', 'label', 'ok', 'detail' );
        };
        $add( 'services', 'Services', (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}yatoon_services WHERE is_active=1" ) > 0, 'At least one active service' );
        $add( 'staff', 'Bookable team', (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}yatoon_staff WHERE is_active=1 AND is_bookable=1" ) > 0, 'At least one bookable employee' );
        $add( 'reminders', 'Reminder scheduler', (bool) wp_next_scheduled( 'yatoon_send_reminders' ), 'WordPress Cron reminder event' );
        $add( 'waitlist', 'Waitlist scheduler', (bool) wp_next_scheduled( 'yatoon_check_waitlist_availability' ), 'Opening checks every 15 minutes' );
        $sync_needed = in_array( get_option( 'yatoon_booking_mode', 'local' ), array( 'square', 'hybrid' ), true );
        $add( 'sync', 'Booking sync', ! $sync_needed || (bool) wp_next_scheduled( 'yatoon_sync_square_bookings_only' ), $sync_needed ? 'Square booking sync event' : 'Local mode does not require external sync' );
        $add( 'email', 'Business email', (bool) is_email( get_option( 'yatoon_business_email', get_option( 'admin_email' ) ) ), 'Valid notification address' );
        $add( 'payment', 'Payment requests', (bool) ( get_option( 'yatoon_square_checkout_url' ) || get_option( 'yatoon_payment_request_url' ) ), 'Hosted checkout or payment request URL' );
        $add( 'https', 'Secure website', is_ssl(), 'HTTPS protects customer information' );
        return $checks;
    }

    public static function capture_health_snapshot() {
        update_option( self::HEALTH_OPTION, array( 'time' => current_time( 'mysql' ), 'checks' => self::health_checks() ), false );
    }

    public static function cli_smoke_test() {
        global $wpdb;
        $required_tables = array( 'yatoon_bookings', 'yatoon_services', 'yatoon_staff', 'yatoon_finance_ledger' );
        $failed = false;
        foreach ( $required_tables as $name ) {
            $table = $wpdb->prefix . $name;
            $exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table;
            $exists ? \WP_CLI::success( "Table {$name}" ) : \WP_CLI::warning( "Missing table {$name}" );
            $failed = $failed || ! $exists;
        }
        foreach ( self::health_checks() as $check ) {
            $check['ok'] ? \WP_CLI::log( "PASS {$check['label']}" ) : \WP_CLI::warning( "CHECK {$check['label']}: {$check['detail']}" );
        }
        if ( $failed ) {
            \WP_CLI::error( 'Yatoon database smoke test failed.' );
        }
        \WP_CLI::success( 'Yatoon 4.1.5 smoke test completed.' );
    }

    public static function run_health_job() {
        self::require_admin();
        check_admin_referer( 'yatoon_run_health_job' );
        $job = sanitize_key( wp_unslash( $_POST['health_job'] ?? '' ) );
        if ( 'reminders' === $job ) {
            do_action( 'yatoon_send_reminders' );
        } elseif ( 'waitlist' === $job ) {
            do_action( 'yatoon_check_waitlist_availability' );
        } elseif ( 'sync' === $job ) {
            do_action( 'yatoon_sync_square_bookings_only' );
        }
        self::capture_health_snapshot();
        self::redirect( 'reliability', 'ran' );
    }

    public static function bulk_update_booking_status() {
        check_ajax_referer( 'yatoon_admin_nonce', 'nonce' );
        self::require_admin();
        $ids = array_values( array_filter( array_map( 'absint', (array) ( $_POST['booking_ids'] ?? array() ) ) ) );
        $status = sanitize_key( wp_unslash( $_POST['status'] ?? '' ) );
        if ( ! $ids || ! in_array( $status, array( 'pending', 'confirmed', 'completed', 'no_show', 'cancelled' ), true ) ) {
            wp_send_json_error( array( 'message' => 'Invalid bulk update.' ) );
        }
        global $wpdb;
        foreach ( $ids as $id ) {
            $old = (string) $wpdb->get_var( $wpdb->prepare( "SELECT status FROM {$wpdb->prefix}yatoon_bookings WHERE id=%d", $id ) );
            $wpdb->update( $wpdb->prefix . 'yatoon_bookings', array( 'status' => $status ), array( 'id' => $id ), array( '%s' ), array( '%d' ) );
            do_action( 'yatoon_booking_status_changed', $id, $status, $old );
        }
        wp_send_json_success( array( 'message' => sprintf( '%d bookings updated.', count( $ids ) ) ) );
    }

    public static function export_ledger() {
        self::require_admin();
        check_admin_referer( 'yatoon_export_ledger' );
        global $wpdb;
        $rows = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}yatoon_finance_ledger ORDER BY created_at DESC", ARRAY_A );
        nocache_headers();
        header( 'Content-Type: text/csv; charset=utf-8' );
        header( 'Content-Disposition: attachment; filename=yatoon-finance-ledger-' . gmdate( 'Y-m-d' ) . '.csv' );
        $out = fopen( 'php://output', 'w' );
        fputcsv( $out, array( 'ID', 'Booking', 'Type', 'Amount', 'Method', 'Reference', 'Note', 'Created' ) );
        foreach ( $rows as $row ) {
            fputcsv( $out, array( $row['id'], $row['booking_id'], $row['entry_type'], $row['amount'], $row['method'], $row['reference'], $row['note'], $row['created_at'] ) );
        }
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
        fclose( $out );
        exit;
    }

    public static function print_invoice() {
        self::require_admin();
        check_admin_referer( 'yatoon_print_invoice' );
        global $wpdb;
        $id = absint( $_GET['booking_id'] ?? 0 );
        $booking = $wpdb->get_row( $wpdb->prepare(
            "SELECT b.*, s.name service_name, st.name staff_name FROM {$wpdb->prefix}yatoon_bookings b
             LEFT JOIN {$wpdb->prefix}yatoon_services s ON s.id=b.service_id
             LEFT JOIN {$wpdb->prefix}yatoon_staff st ON st.id=b.staff_id WHERE b.id=%d",
            $id
        ) );
        if ( ! $booking ) {
            wp_die( 'Booking not found.' );
        }
        $tax_rate = (float) get_option( 'yatoon_default_tax_rate', 0 );
        $fee = (float) get_option( 'yatoon_default_service_fee', 0 );
        $subtotal = (float) $booking->total_price;
        $tax = round( $subtotal * $tax_rate / 100, 2 );
        $total = $subtotal + $tax + $fee;
        $prefix = get_option( 'yatoon_invoice_prefix', 'YTN' );
        ?>
        <!doctype html><html><head><meta charset="utf-8"><title><?php echo esc_html( $prefix . '-' . $id ); ?></title>
        <style>body{font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#172033;margin:40px}.invoice{max-width:760px;margin:auto}.head{display:flex;justify-content:space-between;border-bottom:2px solid #172033;padding-bottom:20px}.muted{color:#697386}.row{display:flex;justify-content:space-between;padding:12px 0;border-bottom:1px solid #e7eaf0}.total{font-size:20px;font-weight:800}.print{margin:24px 0;padding:10px 16px}@media print{.print{display:none}}</style></head>
        <body><main class="invoice"><button class="print" onclick="window.print()">Print / Save PDF</button><div class="head"><div><h1><?php echo esc_html( get_option( 'yatoon_business_name', get_bloginfo( 'name' ) ) ); ?></h1><div class="muted"><?php echo esc_html( get_option( 'yatoon_business_address', '' ) ); ?></div></div><div><strong>Invoice <?php echo esc_html( $prefix . '-' . $id ); ?></strong><div class="muted"><?php echo esc_html( current_time( 'M j, Y' ) ); ?></div></div></div>
        <h3>Bill to</h3><p><?php echo esc_html( $booking->customer_name ); ?><br><?php echo esc_html( $booking->customer_email ); ?><br><?php echo esc_html( $booking->customer_phone ); ?></p>
        <div class="row"><span><?php echo esc_html( $booking->service_name ); ?><br><small class="muted"><?php echo esc_html( $booking->staff_name . ' · ' . $booking->start_time ); ?></small></span><strong>$<?php echo esc_html( number_format( $subtotal, 2 ) ); ?></strong></div>
        <div class="row"><span>Tax (<?php echo esc_html( number_format( $tax_rate, 2 ) ); ?>%)</span><span>$<?php echo esc_html( number_format( $tax, 2 ) ); ?></span></div>
        <div class="row"><span>Service fee</span><span>$<?php echo esc_html( number_format( $fee, 2 ) ); ?></span></div>
        <div class="row total"><span>Total</span><span>$<?php echo esc_html( number_format( $total, 2 ) ); ?></span></div>
        <p class="muted">Payment status: <?php echo esc_html( ucwords( str_replace( '_', ' ', $booking->payment_status ?: 'unpaid' ) ) ); ?></p></main></body></html>
        <?php
        exit;
    }

    public static function render_page() {
        self::require_admin();
        global $wpdb;
        $tab = sanitize_key( wp_unslash( $_GET['tab'] ?? 'reliability' ) );
        $tabs = array( 'reliability' => 'Reliability', 'finance' => 'Finance', 'automation' => 'Automation' );
        if ( ! isset( $tabs[ $tab ] ) ) {
            $tab = 'reliability';
        }
        $base = admin_url( 'admin.php?page=yatoon-operations' );
        ?>
        <div class="wrap yatoon-ops"><div class="yatoon-ops-head"><div><span class="yatoon-eyebrow">Daily operations</span><h1>Operations Center</h1><p>Monitor booking health, money movement, and routine follow-up from one place.</p></div><a class="button button-primary" href="<?php echo esc_url( admin_url( 'admin.php?page=sbs-bookings' ) ); ?>">Manage bookings</a></div>
        <?php if ( ! empty( $_GET['yatoon_notice'] ) ) : ?><div class="notice notice-success is-dismissible"><p>Operations updated.</p></div><?php endif; ?>
        <nav class="nav-tab-wrapper"><?php foreach ( $tabs as $key => $label ) : ?><a class="nav-tab <?php echo $tab === $key ? 'nav-tab-active' : ''; ?>" href="<?php echo esc_url( add_query_arg( 'tab', $key, $base ) ); ?>"><?php echo esc_html( $label ); ?></a><?php endforeach; ?></nav>
        <?php
        if ( 'finance' === $tab ) {
            self::render_finance( $wpdb );
        } elseif ( 'automation' === $tab ) {
            self::render_automation();
        } else {
            self::render_reliability();
        }
        ?></div><?php
    }

    private static function render_reliability() {
        $checks = self::health_checks();
        $passed = count( array_filter( $checks, function( $check ) { return $check['ok']; } ) );
        ?>
        <div class="yatoon-ops-kpis"><div><strong><?php echo esc_html( $passed . '/' . count( $checks ) ); ?></strong><span>checks passing</span></div><div><strong><?php echo esc_html( wp_next_scheduled( 'yatoon_send_reminders' ) ? human_time_diff( time(), wp_next_scheduled( 'yatoon_send_reminders' ) ) : 'Not scheduled' ); ?></strong><span>next reminder run</span></div><div><strong><?php echo esc_html( wp_timezone_string() ?: 'UTC' ); ?></strong><span>site timezone</span></div></div>
        <section class="yatoon-ops-panel"><div class="panel-title"><div><h2>System checks</h2><p>Issues here can stop appointments, reminders, or payments from working normally.</p></div><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"><?php wp_nonce_field( 'yatoon_run_health_job' ); ?><input type="hidden" name="action" value="yatoon_run_health_job"><input type="hidden" name="health_job" value="reminders"><button class="button">Run reminders now</button></form></div>
        <div class="yatoon-check-list"><?php foreach ( $checks as $check ) : ?><div class="yatoon-check"><span class="dashicons <?php echo $check['ok'] ? 'dashicons-yes-alt ok' : 'dashicons-warning warn'; ?>"></span><div><strong><?php echo esc_html( $check['label'] ); ?></strong><small><?php echo esc_html( $check['detail'] ); ?></small></div><span class="yatoon-status"><?php echo $check['ok'] ? 'Ready' : 'Needs attention'; ?></span></div><?php endforeach; ?></div></section>
        <section class="yatoon-ops-panel"><h2>Manual jobs</h2><div class="yatoon-job-row"><?php foreach ( array( 'sync' => 'Sync bookings', 'waitlist' => 'Check waitlist', 'reminders' => 'Send due reminders' ) as $job => $label ) : ?><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"><?php wp_nonce_field( 'yatoon_run_health_job' ); ?><input type="hidden" name="action" value="yatoon_run_health_job"><input type="hidden" name="health_job" value="<?php echo esc_attr( $job ); ?>"><button class="button"><?php echo esc_html( $label ); ?></button></form><?php endforeach; ?></div></section>
        <?php self::styles(); ?>
        <?php
    }

    private static function render_finance( $wpdb ) {
        $stats = $wpdb->get_row( "SELECT COALESCE(SUM(total_price),0) scheduled,
            COALESCE(SUM(CASE WHEN payment_status IN ('unpaid','') OR payment_status IS NULL THEN total_price ELSE 0 END),0) outstanding,
            COALESCE(SUM(CASE WHEN payment_status IN ('paid_square_pos','deposit_paid') THEN total_price ELSE 0 END),0) recorded
            FROM {$wpdb->prefix}yatoon_bookings WHERE status <> 'cancelled'" );
        $ledger = $wpdb->get_results( "SELECT l.*, b.customer_name FROM {$wpdb->prefix}yatoon_finance_ledger l LEFT JOIN {$wpdb->prefix}yatoon_bookings b ON b.id=l.booking_id ORDER BY l.created_at DESC LIMIT 100" );
        ?>
        <div class="yatoon-ops-kpis"><div><strong>$<?php echo esc_html( number_format( (float) $stats->scheduled, 2 ) ); ?></strong><span>scheduled value</span></div><div><strong>$<?php echo esc_html( number_format( (float) $stats->outstanding, 2 ) ); ?></strong><span>outstanding</span></div><div><strong>$<?php echo esc_html( number_format( (float) $stats->recorded, 2 ) ); ?></strong><span>marked paid/deposit</span></div></div>
        <div class="yatoon-ops-grid"><section class="yatoon-ops-panel"><h2>Invoice defaults</h2><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"><?php wp_nonce_field( 'yatoon_finance_settings' ); ?><input type="hidden" name="action" value="yatoon_save_finance_settings"><label>Invoice prefix<input name="invoice_prefix" value="<?php echo esc_attr( get_option( 'yatoon_invoice_prefix', 'YTN' ) ); ?>"></label><label>Default tax rate (%)<input type="number" step="0.01" min="0" max="100" name="tax_rate" value="<?php echo esc_attr( get_option( 'yatoon_default_tax_rate', 0 ) ); ?>"></label><label>Service fee ($)<input type="number" step="0.01" min="0" name="service_fee" value="<?php echo esc_attr( get_option( 'yatoon_default_service_fee', 0 ) ); ?>"></label><button class="button button-primary">Save defaults</button></form></section>
        <section class="yatoon-ops-panel"><h2>Record transaction</h2><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"><?php wp_nonce_field( 'yatoon_add_ledger_entry' ); ?><input type="hidden" name="action" value="yatoon_add_ledger_entry"><label>Booking ID<input type="number" min="1" name="booking_id"></label><label>Type<select name="entry_type"><option value="payment">Payment</option><option value="deposit">Deposit</option><option value="refund">Refund</option><option value="fee">Fee</option><option value="adjustment">Adjustment</option></select></label><label>Amount ($)<input type="number" step="0.01" name="amount" required></label><label>Method<select name="method"><option value="cash">Cash</option><option value="square">Square</option><option value="stripe">Stripe</option><option value="card">Other card</option><option value="manual">Manual</option></select></label><label>Reference<input name="reference"></label><label>Note<textarea name="note" rows="2"></textarea></label><button class="button button-primary">Add entry</button></form></section></div>
        <section class="yatoon-ops-panel"><div class="panel-title"><div><h2>Finance ledger</h2><p>Append-only record of payments, deposits, refunds, fees, and adjustments.</p></div><a class="button" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=yatoon_export_ledger' ), 'yatoon_export_ledger' ) ); ?>">Export CSV</a></div><div class="yatoon-table-scroll"><table class="widefat striped"><thead><tr><th>Date</th><th>Booking</th><th>Customer</th><th>Type</th><th>Method</th><th>Reference</th><th class="num">Amount</th></tr></thead><tbody><?php if ( ! $ledger ) : ?><tr><td colspan="7">No ledger entries yet. New payment changes will appear here automatically.</td></tr><?php endif; ?><?php foreach ( $ledger as $row ) : ?><tr><td><?php echo esc_html( $row->created_at ); ?></td><td><?php echo $row->booking_id ? '#' . esc_html( $row->booking_id ) : '-'; ?></td><td><?php echo esc_html( $row->customer_name ?: '-' ); ?></td><td><?php echo esc_html( ucwords( $row->entry_type ) ); ?></td><td><?php echo esc_html( ucwords( $row->method ) ); ?></td><td><?php echo esc_html( $row->reference ); ?></td><td class="num <?php echo (float) $row->amount < 0 ? 'negative' : ''; ?>">$<?php echo esc_html( number_format( (float) $row->amount, 2 ) ); ?></td></tr><?php endforeach; ?></tbody></table></div></section>
        <?php self::styles(); ?>
        <?php
    }

    private static function render_automation() {
        $rows = (array) get_option( self::WORKFLOWS_OPTION, array() );
        ?>
        <div class="yatoon-ops-grid yatoon-auto-grid"><section class="yatoon-ops-panel"><h2>New automation</h2><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"><?php wp_nonce_field( 'yatoon_save_workflow' ); ?><input type="hidden" name="action" value="yatoon_save_workflow"><label>Name<input name="name" required placeholder="Confirmed booking follow-up"></label><label>When<select name="event"><option value="booking_created">Booking is created</option><option value="booking_status">Booking status changes</option><option value="payment_status">Payment status changes</option></select></label><label>Only when value equals<input name="condition" placeholder="Optional: confirmed, completed, refunded"></label><label>Wait before running (minutes)<input type="number" min="0" max="43200" name="delay_minutes" value="0"></label><label>Then<select name="workflow_action"><option value="email_admin">Email administrator</option><option value="email_customer">Email customer</option><option value="webhook">Send webhook</option><option value="internal_note">Add internal booking note</option></select></label><label>Webhook URL (webhook only)<input type="url" name="target"></label><label>Subject<input name="subject" value="Booking update #{{booking_id}}"></label><label>Message<textarea name="message" rows="6">Hi {{customer_name}},

Your {{service}} appointment with {{staff}} is now {{status}}.

Appointment: {{start_time}}
Total: ${{total}}</textarea></label><p class="description">Available: {{booking_id}}, {{customer_name}}, {{service}}, {{staff}}, {{status}}, {{start_time}}, {{total}}</p><button class="button button-primary">Create automation</button></form></section>
        <section class="yatoon-ops-panel"><h2>Active automations</h2><?php if ( ! $rows ) : ?><div class="yatoon-empty"><span class="dashicons dashicons-controls-repeat"></span><strong>No automations yet</strong><p>Create one focused rule first, then expand only when it saves real work.</p></div><?php endif; ?><?php foreach ( $rows as $row ) : ?><article class="yatoon-workflow"><div><strong><?php echo esc_html( $row['name'] ); ?></strong><p><?php echo esc_html( ucwords( str_replace( '_', ' ', $row['event'] ) ) ); ?> → <?php echo esc_html( ucwords( str_replace( '_', ' ', $row['action'] ) ) ); ?></p><?php if ( ! empty( $row['condition'] ) ) : ?><small>Condition: <?php echo esc_html( $row['condition'] ); ?></small><?php endif; ?><?php if ( ! empty( $row['delay_minutes'] ) ) : ?><small> · Delay: <?php echo esc_html( absint( $row['delay_minutes'] ) ); ?> min</small><?php endif; ?></div><a class="button button-small" href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin-post.php?action=yatoon_delete_workflow&workflow_id=' . rawurlencode( $row['id'] ) ), 'yatoon_delete_workflow' ) ); ?>">Delete</a></article><?php endforeach; ?></section></div>
        <?php self::styles(); ?>
        <?php
    }

    private static function styles() {
        ?><style>
        .yatoon-ops{max-width:1320px}.yatoon-ops-head{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin:22px 0}.yatoon-ops-head h1{margin:3px 0 6px;font-size:30px}.yatoon-ops-head p{margin:0;color:#667085}.yatoon-eyebrow{text-transform:uppercase;font-size:11px;font-weight:800;color:#a83262}.yatoon-ops .nav-tab-wrapper{margin-bottom:20px}.yatoon-ops-kpis{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;margin:18px 0}.yatoon-ops-kpis>div,.yatoon-ops-panel{background:#fff;border:1px solid #dfe3ea;border-radius:8px}.yatoon-ops-kpis>div{padding:20px}.yatoon-ops-kpis strong{display:block;font-size:25px}.yatoon-ops-kpis span{color:#667085}.yatoon-ops-panel{padding:22px;margin-bottom:16px}.yatoon-ops-panel h2{margin:0 0 8px;font-size:18px}.panel-title{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:14px}.panel-title p{margin:3px 0;color:#667085}.yatoon-check-list{border-top:1px solid #eaecf0}.yatoon-check{display:grid;grid-template-columns:28px 1fr auto;align-items:center;padding:14px 0;border-bottom:1px solid #eaecf0}.yatoon-check small{display:block;color:#667085;margin-top:2px}.yatoon-check .ok{color:#15803d}.yatoon-check .warn{color:#b45309}.yatoon-status{font-size:12px;font-weight:700}.yatoon-job-row{display:flex;flex-wrap:wrap;gap:10px}.yatoon-ops-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.yatoon-ops-panel label{display:block;font-weight:600;margin:0 0 13px}.yatoon-ops-panel input,.yatoon-ops-panel select,.yatoon-ops-panel textarea{display:block;width:100%;max-width:none;margin-top:5px}.yatoon-table-scroll{overflow:auto}.yatoon-table-scroll table{min-width:780px}.yatoon-table-scroll .num{text-align:right;font-weight:700}.yatoon-table-scroll .negative{color:#b42318}.yatoon-workflow{display:flex;justify-content:space-between;gap:12px;padding:15px 0;border-bottom:1px solid #eaecf0}.yatoon-workflow p{margin:3px 0;color:#475467}.yatoon-empty{text-align:center;padding:40px 20px;color:#667085}.yatoon-empty .dashicons{font-size:30px;width:30px;height:30px}.yatoon-empty strong{display:block;color:#172033;margin-top:8px}@media(max-width:782px){.yatoon-ops-head{display:block}.yatoon-ops-head .button{margin-top:14px}.yatoon-ops-kpis,.yatoon-ops-grid{grid-template-columns:1fr}.panel-title{display:block}.panel-title form,.panel-title .button{margin-top:10px}.yatoon-check{grid-template-columns:26px 1fr}.yatoon-status{grid-column:2}.yatoon-ops-panel{padding:16px}}
        </style><?php
    }
}
