<?php
/**
 * REST API — secondary surface mirroring the primary AJAX handlers.
 *
 * Maintained as fragments so the optional routes/callbacks (leave*, attendance*)
 * can be assembled separately — mirrors the EMPR_Ajax fragment split:
 *
 *   class-emr-rest-api-core.php     opens `class EMPR_REST_API {` + base routes/
 *                                   callbacks, NO closing brace
 *   (optional companion fragment)   additional routes/callbacks (no <?php, no
 *                                   class declaration, no brace)
 *   class-emr-rest-api-close.php    the single closing `}`
 *
 * The generated includes/class-emr-rest-api.php is a build artifact (git-ignored);
 * never edit it by hand — edit the fragments and re-run build/concat-rest.php.
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class EMPR_REST_API {

    const NS = 'emp-roster/v1';

    public static function init() {
        add_action( 'rest_api_init', array( __CLASS__, 'register' ) );
    }

    public static function register() {
        $m = __CLASS__;

        register_rest_route( self::NS, '/shifts', array(
            array( 'methods' => 'GET',  'callback' => array( $m, 'shifts_index' ),  'permission_callback' => array( $m, 'logged_in' ) ),
            array( 'methods' => 'POST', 'callback' => array( $m, 'shifts_create' ), 'permission_callback' => array( $m, 'is_manager' ) ),
        ) );
        register_rest_route( self::NS, '/shifts/(?P<id>\d+)', array(
            array( 'methods' => 'GET',    'callback' => array( $m, 'shifts_show' ),   'permission_callback' => array( $m, 'logged_in' ) ),
            array( 'methods' => 'PUT',    'callback' => array( $m, 'shifts_update' ), 'permission_callback' => array( $m, 'is_manager' ) ),
            array( 'methods' => 'DELETE', 'callback' => array( $m, 'shifts_delete' ), 'permission_callback' => array( $m, 'is_manager' ) ),
        ) );
        register_rest_route( self::NS, '/shifts/(?P<id>\d+)/assign',   array( 'methods' => 'POST', 'callback' => array( $m, 'shifts_assign' ),   'permission_callback' => array( $m, 'is_manager' ) ) );
        register_rest_route( self::NS, '/shifts/(?P<id>\d+)/unassign', array( 'methods' => 'POST', 'callback' => array( $m, 'shifts_unassign' ), 'permission_callback' => array( $m, 'is_manager' ) ) );
        register_rest_route( self::NS, '/shifts/(?P<id>\d+)/sync',     array( 'methods' => 'POST', 'callback' => array( $m, 'shifts_sync' ),     'permission_callback' => array( $m, 'is_manager' ) ) );

        register_rest_route( self::NS, '/availability', array(
            array( 'methods' => 'GET',  'callback' => array( $m, 'avail_show' ), 'permission_callback' => array( $m, 'logged_in' ) ),
            array( 'methods' => 'POST', 'callback' => array( $m, 'avail_save' ), 'permission_callback' => array( $m, 'logged_in' ) ),
        ) );
        register_rest_route( self::NS, '/availability/all', array( 'methods' => 'GET',  'callback' => array( $m, 'avail_all' ),  'permission_callback' => array( $m, 'is_manager' ) ) );

        register_rest_route( self::NS, '/staff',     array( 'methods' => 'GET', 'callback' => array( $m, 'staff_index' ),  'permission_callback' => array( $m, 'can_view_all_staff' ) ) );
        register_rest_route( self::NS, '/dashboard', array( 'methods' => 'GET', 'callback' => array( $m, 'dashboard' ),    'permission_callback' => array( $m, 'logged_in' ) ) );
        register_rest_route( self::NS, '/settings',  array( 'methods' => 'GET', 'callback' => array( $m, 'settings_get' ), 'permission_callback' => array( $m, 'logged_in' ) ) );

        // Optional extension point. Additional routes may be supplied by a companion
        // fragment; when none is present this class registers exactly the routes above.
        if ( method_exists( __CLASS__, 'register_optional_routes' ) ) {
            self::register_optional_routes();
        }
    }

    public static function logged_in()         { return is_user_logged_in(); }
    public static function is_manager()        { return EMPR_Roles::is_manager(); }
    public static function can_view_all_staff() { return EMPR_Roles::can_view_all(); }

    /* ── Shifts ── */
    public static function shifts_index( $req ) {
        $args = array();
        if ( ! EMPR_Roles::is_manager() ) $args['user_id'] = get_current_user_id();
        if ( $v = $req->get_param('start') )  $args['start']  = $v;
        if ( $v = $req->get_param('end') )    $args['end']    = $v;
        if ( $v = $req->get_param('status') ) $args['status'] = $v;
        return rest_ensure_response( EMPR_Shifts::query( $args ) );
    }
    public static function shifts_show( $req ) {
        global $wpdb;
        $shift_id = absint( $req->get_param( 'id' ) );
        $user_id  = get_current_user_id();

        if ( ! EMPR_Roles::is_manager() && ! EMPR_Roles::is_admin() ) {
            $assigned = $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM {$wpdb->prefix}emr_assignments WHERE shift_id = %d AND user_id = %d LIMIT 1",
                $shift_id,
                $user_id
            ) );
            if ( ! $assigned ) {
                return new WP_Error(
                    'rest_forbidden',
                    __( 'You do not have permission to view this shift.', 'employee-roster' ),
                    array( 'status' => 403 )
                );
            }
        }

        $shift = EMPR_Shifts::get( $shift_id );
        if ( ! $shift ) return new WP_Error( 'not_found', 'Shift not found.', array( 'status' => 404 ) );
        $shift->assignments = EMPR_Assignments::for_shift( $shift_id );
        return rest_ensure_response( $shift );
    }
    public static function shifts_create( $req ) {
        $data = EMPR_Shifts::sanitize( (array) $req->get_json_params() );
        if ( is_wp_error( $data ) ) return $data;
        $id = EMPR_Shifts::create( $data );
        return rest_ensure_response( array( 'id' => $id, 'message' => 'Shift created.' ) );
    }
    public static function shifts_update( $req ) {
        $data = EMPR_Shifts::sanitize( (array) $req->get_json_params() );
        if ( is_wp_error( $data ) ) return $data;
        EMPR_Shifts::update( (int) $req['id'], $data );
        return rest_ensure_response( array( 'message' => 'Shift updated.' ) );
    }
    public static function shifts_delete( $req ) {
        EMPR_Shifts::delete( (int) $req['id'] );
        return rest_ensure_response( array( 'message' => 'Shift deleted.' ) );
    }
    public static function shifts_assign( $req ) {
        $body   = (array) $req->get_json_params();
        $uid    = (int) ( isset( $body['user_id'] ) ? $body['user_id'] : 0 );
        $result = EMPR_Assignments::assign( (int) $req['id'], $uid );
        if ( is_wp_error( $result ) ) return $result;
        return rest_ensure_response( array( 'message' => 'User assigned.' ) );
    }
    public static function shifts_unassign( $req ) {
        $body = (array) $req->get_json_params();
        $uid  = (int) ( isset( $body['user_id'] ) ? $body['user_id'] : 0 );
        EMPR_Assignments::unassign( (int) $req['id'], $uid );
        return rest_ensure_response( array( 'message' => 'User unassigned.' ) );
    }
    public static function shifts_sync( $req ) {
        $body     = (array) $req->get_json_params();
        $user_ids = array_map( 'intval', isset( $body['user_ids'] ) ? $body['user_ids'] : array() );
        EMPR_Assignments::sync( (int) $req['id'], $user_ids );
        return rest_ensure_response( array( 'message' => 'Assignments synced.' ) );
    }

    /* ── Availability ── */
    public static function avail_show( $req ) {
        $uid = ( EMPR_Roles::is_manager() && $req->get_param('user_id') )
            ? (int) $req->get_param('user_id') : get_current_user_id();
        return rest_ensure_response( EMPR_Availability::for_user( $uid ) );
    }
    public static function avail_save( $req ) {
        $body  = (array) $req->get_json_params();
        $uid   = ( EMPR_Roles::is_manager() && ! empty( $body['user_id'] ) )
            ? (int) $body['user_id'] : get_current_user_id();
        $slots = isset( $body['slots'] ) ? (array) $body['slots'] : array();
        EMPR_Availability::save( $uid, $slots );
        return rest_ensure_response( array( 'message' => 'Availability saved.' ) );
    }
    public static function avail_all() {
        return rest_ensure_response( EMPR_Availability::all_staff() );
    }

    /* ── Staff ── */
    public static function staff_index() {
        $users  = get_users( array( 'role__in' => array( 'emr_employee', 'emr_manager', 'administrator' ) ) );
        $result = array();
        foreach ( $users as $u ) {
            $result[] = array(
                'id'           => $u->ID,
                'display_name' => $u->display_name,
                'email'        => $u->user_email,
                'roles'        => $u->roles,
            );
        }
        return rest_ensure_response( $result );
    }

    /* ── Dashboard ── */
    public static function dashboard() {
        $uid       = get_current_user_id();
        $today     = current_time( 'Y-m-d' );
        $dow       = (int) current_time( 'N' ); // 1=Mon, 7=Sun
        $week_mon  = wp_date( 'Y-m-d', strtotime( current_time( 'Y-m-d' ) . ' -' . ( $dow - 1 ) . ' days' ) );
        $week_sun  = wp_date( 'Y-m-d', strtotime( $week_mon . ' +6 days' ) );

        $my_shifts = EMPR_Shifts::query( array(
            'user_id' => $uid,
            'start'   => $today . ' 00:00:00',
            'end'     => $week_sun . ' 23:59:59',
        ) );

        // Attendance session data is supplied by the optional dashboard_attendance()
        // seam when it is available. Without it the dashboard reports no active
        // session and zero hours, which is the correct result for a build that does
        // not track clock sessions.
        $session = null;
        $hours   = 0;
        if ( method_exists( __CLASS__, 'dashboard_attendance' ) ) {
            $att     = self::dashboard_attendance( $uid, $week_mon, $week_sun );
            $session = $att['session'];
            $hours   = $att['hours'];
        }

        $payload = array(
            'my_upcoming_shifts' => $my_shifts,
            'hours_this_week'    => $hours,
            'clocked_in'         => (bool) $session,
            'session'            => $session,
            'pending_leave_own'  => count( EMPR_Leave::query( array( 'user_id' => $uid, 'status' => 'pending' ) ) ),
        );

        if ( EMPR_Roles::is_manager() ) {
            $payload['pending_leave_all'] = count( EMPR_Leave::query( array( 'status' => 'pending' ) ) );
            $payload['shifts_today']      = count( EMPR_Shifts::query( array(
                'start'  => $today . ' 00:00:00',
                'end'    => $today . ' 23:59:59',
                'status' => 'published',
            ) ) );
            $payload['total_staff'] = count( get_users( array( 'role__in' => array( 'emr_employee', 'emr_manager' ) ) ) );
        }

        return rest_ensure_response( $payload );
    }

    /* ── Settings ── */
    public static function settings_get() {
        return rest_ensure_response( EMPR_Settings::for_js() );
    }
}
