<?php
/**
 * Class LSC_Sessions
 *
 * Logs chatter login/logout events and provides the admin activity log.
 */
class LSC_Sessions {

    public function __construct() {
        // Hook into WordPress login/logout actions.
        // wp_login fires with ( $user_login, $user ) after successful login.
        add_action( 'wp_login',  [ $this, 'on_login'  ], 10, 2 );

        // wp_logout fires with ( $user_id ) after the session is destroyed.
        add_action( 'wp_logout', [ $this, 'on_logout' ], 10, 1 );
    }

    /* ------------------------------------------------------------------
     * Table name
     * ------------------------------------------------------------------ */

    private static function table() {
        global $wpdb;
        return $wpdb->prefix . 'lsc_sessions';
    }

    /* ------------------------------------------------------------------
     * Hook: user logs in
     * ------------------------------------------------------------------ */

    public function on_login( $user_login, $user ) {
        // Only log chatters (and admins using the chatter dashboard).
        if ( ! in_array( 'chatter', (array) $user->roles, true )
            && ! user_can( $user, 'administrator' ) ) {
            return;
        }

        global $wpdb;

        $wpdb->insert(
            self::table(),
            [
                'user_id'      => (int) $user->ID,
                'user_login'   => sanitize_text_field( $user->user_login ),
                'display_name' => sanitize_text_field( $user->display_name ),
                'login_at'     => current_time( 'mysql' ),
                'logout_at'    => null,
                'ip_address'   => self::get_ip(),
            ],
            [ '%d', '%s', '%s', '%s', null, '%s' ]
        );
    }

    /* ------------------------------------------------------------------
     * Hook: user logs out
     * ------------------------------------------------------------------ */

    public function on_logout( $user_id ) {
        global $wpdb;

        // Find the most recent open session for this user.
        $session = $wpdb->get_row(
            $wpdb->prepare(
                'SELECT id FROM ' . self::table() . ' WHERE user_id = %d AND logout_at IS NULL ORDER BY login_at DESC LIMIT 1',
                (int) $user_id
            )
        );

        if ( $session ) {
            $wpdb->update(
                self::table(),
                [ 'logout_at' => current_time( 'mysql' ) ],
                [ 'id'        => (int) $session->id ],
                [ '%s' ],
                [ '%d' ]
            );
        }
    }

    /* ------------------------------------------------------------------
     * Query helpers for the admin view
     * ------------------------------------------------------------------ */

    /**
     * Get paginated session log.
     *
     * @param array $args { user_id, limit, offset, orderby, order }
     * @return array
     */
    public static function get_sessions( $args = [] ) {
        global $wpdb;

        $defaults = [
            'user_id' => 0,
            'limit'   => 25,
            'offset'  => 0,
            'orderby' => 'login_at',
            'order'   => 'DESC',
        ];
        $args = wp_parse_args( $args, $defaults );

        $where  = '1=1';
        $values = [];

        if ( ! empty( $args['user_id'] ) ) {
            $where    .= ' AND user_id = %d';
            $values[]  = (int) $args['user_id'];
        }

        $orderby = in_array( $args['orderby'], [ 'id', 'login_at', 'logout_at', 'user_login' ], true )
            ? $args['orderby'] : 'login_at';
        $order   = 'ASC' === strtoupper( $args['order'] ) ? 'ASC' : 'DESC';

        $values[] = (int) $args['limit'];
        $values[] = (int) $args['offset'];

        $sql = "SELECT * FROM " . self::table() . " WHERE {$where} ORDER BY {$orderby} {$order} LIMIT %d OFFSET %d";

        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
        return $wpdb->get_results( $wpdb->prepare( $sql, $values ) );
    }

    /**
     * Total session count (for pagination).
     *
     * @param int $user_id Optional filter.
     * @return int
     */
    public static function count_sessions( $user_id = 0 ) {
        global $wpdb;

        if ( $user_id ) {
            return (int) $wpdb->get_var( $wpdb->prepare(
                'SELECT COUNT(*) FROM ' . self::table() . ' WHERE user_id = %d',
                (int) $user_id
            ) );
        }
        return (int) $wpdb->get_var( 'SELECT COUNT(*) FROM ' . self::table() );
    }

    /**
     * Delete a single session record.
     *
     * @param int $id
     * @return bool
     */
    public static function delete_session( $id ) {
        global $wpdb;
        return (bool) $wpdb->delete( self::table(), [ 'id' => (int) $id ], [ '%d' ] );
    }

    /**
     * Delete ALL session records (clear log).
     *
     * @return bool
     */
    public static function clear_all() {
        global $wpdb;
        return (bool) $wpdb->query( 'TRUNCATE TABLE ' . self::table() );
    }

    /**
     * Calculate duration string from two datetime strings.
     *
     * @param string      $login_at  MySQL datetime.
     * @param string|null $logout_at MySQL datetime or null.
     * @return string Human-readable duration.
     */
    public static function duration( $login_at, $logout_at ) {
        if ( ! $logout_at ) {
            return __( '—', 'live-support-chat' ); // session never closed
        }

        $start   = strtotime( $login_at );
        $end     = strtotime( $logout_at );
        $seconds = max( 0, $end - $start );

        if ( $seconds < 60 ) {
            return sprintf( _n( '%d second', '%d seconds', $seconds, 'live-support-chat' ), $seconds );
        }
        if ( $seconds < 3600 ) {
            $m = (int) floor( $seconds / 60 );
            $s = $seconds % 60;
            return $s > 0
                ? sprintf( __( '%dm %ds', 'live-support-chat' ), $m, $s )
                : sprintf( _n( '%d minute', '%d minutes', $m, 'live-support-chat' ), $m );
        }

        $h = (int) floor( $seconds / 3600 );
        $m = (int) floor( ( $seconds % 3600 ) / 60 );
        return $m > 0
            ? sprintf( __( '%dh %dm', 'live-support-chat' ), $h, $m )
            : sprintf( _n( '%d hour', '%d hours', $h, 'live-support-chat' ), $h );
    }

    /* ------------------------------------------------------------------
     * Helpers
     * ------------------------------------------------------------------ */

    private static function get_ip() {
        $headers = [
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR',
        ];
        foreach ( $headers as $key ) {
            if ( ! empty( $_SERVER[ $key ] ) ) {
                $ip = sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) );
                // Take first IP if comma-separated.
                $ip = trim( explode( ',', $ip )[0] );
                if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
                    return $ip;
                }
            }
        }
        return '';
    }
}
