<?php
/**
 * System Logs REST API Controller.
 *
 * Admin endpoints for viewing, filtering, and cleaning log entries.
 *
 *   GET    /titancart/v1/logs              List/filter logs
 *   GET    /titancart/v1/logs/stats        Counts by level and type
 *   DELETE /titancart/v1/logs              Clean old or all logs
 *   DELETE /titancart/v1/logs/{id}         Delete single entry
 *
 * @package TitanCart\REST\Settings
 */

namespace TitanCart\REST\Settings;

use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

defined( 'ABSPATH' ) || exit;

class LogsController {

    protected string $namespace = 'titancart/v1';

    public function register_routes(): void {

        register_rest_route( $this->namespace, '/logs', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_logs' ],
                'permission_callback' => [ $this, 'check_admin' ],
            ],
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'clean_logs' ],
                'permission_callback' => [ $this, 'check_admin' ],
            ],
        ] );

        register_rest_route( $this->namespace, '/logs/stats', [
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => [ $this, 'get_stats' ],
            'permission_callback' => [ $this, 'check_admin' ],
        ] );

        register_rest_route( $this->namespace, '/logs/(?P<id>\d+)', [
            'methods'             => WP_REST_Server::DELETABLE,
            'callback'            => [ $this, 'delete_one' ],
            'permission_callback' => [ $this, 'check_admin' ],
        ] );
    }

    public function check_admin(): bool {
        return current_user_can( 'manage_options' );
    }

    /* ── GET /logs ────────────────────────────────────────────────────── */

    public function get_logs( WP_REST_Request $request ): WP_REST_Response {
        global $wpdb;
        $table = $wpdb->prefix . 'tc_logs';

        $page     = max( 1, (int) $request->get_param( 'page' ) ?: 1 );
        $per_page = min( 100, max( 10, (int) $request->get_param( 'per_page' ) ?: 50 ) );

        $where  = [];
        $values = [];

        // Filter by level.
        $level = sanitize_text_field( $request->get_param( 'level' ) ?: '' );
        if ( $level && in_array( $level, [ 'debug', 'info', 'notice', 'warning', 'error', 'critical' ], true ) ) {
            $where[]  = 'level = %s';
            $values[] = $level;
        }

        // Filter by type (channel).
        $type = sanitize_text_field( $request->get_param( 'type' ) ?: '' );
        if ( $type ) {
            $where[]  = 'channel = %s';
            $values[] = $type;
        }

        // Filter by action.
        $action = sanitize_text_field( $request->get_param( 'action' ) ?: '' );
        if ( $action ) {
            $where[]  = 'action = %s';
            $values[] = $action;
        }

        // Filter by user_id.
        $user_id = $request->get_param( 'user_id' );
        if ( $user_id !== null && $user_id !== '' ) {
            $where[]  = 'user_id = %d';
            $values[] = (int) $user_id;
        }

        // Search in message.
        $search = sanitize_text_field( $request->get_param( 'search' ) ?: '' );
        if ( $search ) {
            $where[]  = 'message LIKE %s';
            $values[] = '%' . $wpdb->esc_like( $search ) . '%';
        }

        // Date range.
        $date_from = sanitize_text_field( $request->get_param( 'date_from' ) ?: '' );
        if ( $date_from ) {
            $where[]  = 'created_at >= %s';
            $values[] = $date_from . ' 00:00:00';
        }
        $date_to = sanitize_text_field( $request->get_param( 'date_to' ) ?: '' );
        if ( $date_to ) {
            $where[]  = 'created_at <= %s';
            $values[] = $date_to . ' 23:59:59';
        }

        $where_sql = $where ? 'WHERE ' . implode( ' AND ', $where ) : '';

        // Total count.
        $count_sql = "SELECT COUNT(*) FROM {$table} {$where_sql}";
        // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.PreparedSQL.NotPrepared -- placeholders in $where_sql built in lockstep with $values; empty-values case takes the unprepared branch.
        $total     = (int) ( $values ? $wpdb->get_var( $wpdb->prepare( $count_sql, ...$values ) ) : $wpdb->get_var( $count_sql ) );

        // Fetch page.
        $offset    = ( $page - 1 ) * $per_page;
        $query_sql = "SELECT * FROM {$table} {$where_sql} ORDER BY created_at DESC, id DESC LIMIT %d OFFSET %d";
        $all_vals  = array_merge( $values, [ $per_page, $offset ] );
        // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.PreparedSQL.NotPrepared -- $where_sql placeholders + LIMIT/OFFSET %d built in lockstep with $all_vals above.
        $rows      = $wpdb->get_results( $wpdb->prepare( $query_sql, ...$all_vals ), ARRAY_A );

        // Enrich rows: decode context JSON, resolve user display names.
        $user_ids = array_unique( array_filter( array_column( $rows, 'user_id' ) ) );
        $user_map = [];
        if ( $user_ids ) {
            $placeholders = implode( ',', array_fill( 0, count( $user_ids ), '%d' ) );
            $sql = "SELECT ID, display_name, user_email FROM {$wpdb->users} WHERE ID IN ({$placeholders})";
            // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,WordPress.DB.PreparedSQL.NotPrepared -- $placeholders is a %d list built from count($user_ids) (non-empty, guarded above); values passed to prepare().
            $users = $wpdb->get_results( $wpdb->prepare( $sql, ...array_map( 'intval', $user_ids ) ), ARRAY_A );
            foreach ( $users as $u ) {
                $user_map[ (int) $u['ID'] ] = [
                    'id'    => (int) $u['ID'],
                    'name'  => $u['display_name'],
                    'email' => $u['user_email'],
                ];
            }
        }

        foreach ( $rows as &$row ) {
            $row['id']        = (int) $row['id'];
            $row['user_id']   = (int) $row['user_id'];
            $row['object_id'] = (int) $row['object_id'];
            $row['context']   = $row['context'] ? json_decode( $row['context'], true ) : null;
            $row['user']      = $user_map[ $row['user_id'] ] ?? null;
        }
        unset( $row );

        return new WP_REST_Response( [
            'items'      => $rows,
            'total'      => $total,
            'page'       => $page,
            'per_page'   => $per_page,
            'total_pages'=> (int) ceil( $total / $per_page ),
        ] );
    }

    /* ── GET /logs/stats ──────────────────────────────────────────────── */

    public function get_stats( WP_REST_Request $request ): WP_REST_Response {
        global $wpdb;
        $table = $wpdb->prefix . 'tc_logs';

        $total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table}" );

        $by_level = $wpdb->get_results(
            "SELECT level, COUNT(*) AS cnt FROM {$table} GROUP BY level ORDER BY FIELD(level, 'critical','error','warning','notice','info','debug')",
            ARRAY_A
        );

        $by_type = $wpdb->get_results(
            "SELECT channel AS type, COUNT(*) AS cnt FROM {$table} GROUP BY channel ORDER BY cnt DESC",
            ARRAY_A
        );

        // Unique actions for filter dropdown.
        $actions = $wpdb->get_col( "SELECT DISTINCT action FROM {$table} WHERE action != '' ORDER BY action ASC" );

        // Today's count.
        $today = (int) $wpdb->get_var(
            $wpdb->prepare( "SELECT COUNT(*) FROM {$table} WHERE created_at >= %s", gmdate( 'Y-m-d 00:00:00' ) )
        );

        // Errors last 24h.
        $errors_24h = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$table} WHERE level IN ('error','critical') AND created_at >= %s",
                gmdate( 'Y-m-d H:i:s', time() - 86400 )
            )
        );

        // Oldest entry.
        $oldest = $wpdb->get_var( "SELECT MIN(created_at) FROM {$table}" );

        return new WP_REST_Response( [
            'total'      => $total,
            'today'      => $today,
            'errors_24h' => $errors_24h,
            'oldest'     => $oldest,
            'by_level'   => $by_level,
            'by_type'    => $by_type,
            'actions'    => $actions,
        ] );
    }

    /* ── DELETE /logs ──────────────────────────────────────────────────── */

    public function clean_logs( WP_REST_Request $request ): WP_REST_Response {
        $mode = sanitize_text_field( $request->get_param( 'mode' ) ?: 'old' );

        if ( $mode === 'all' ) {
            $deleted = \TitanCart\Core\LogService::cleanup_all();
            \TitanCart\Core\LogService::info( 'database', 'optimize', "Cleaned all logs ({$deleted} entries)", [
                'skip_check' => true,
            ] );
            return new WP_REST_Response( [ 'deleted' => $deleted, 'message' => "Deleted all {$deleted} log entries." ] );
        }

        $days = max( 1, (int) ( $request->get_param( 'days' ) ?: 0 ) );
        $deleted = \TitanCart\Core\LogService::cleanup_old( $days );
        \TitanCart\Core\LogService::info( 'database', 'optimize', "Cleaned logs older than {$days} days ({$deleted} entries)", [
            'skip_check' => true,
        ] );

        return new WP_REST_Response( [ 'deleted' => $deleted, 'message' => "Deleted {$deleted} entries older than {$days} days." ] );
    }

    /* ── DELETE /logs/{id} ────────────────────────────────────────────── */

    public function delete_one( WP_REST_Request $request ): WP_REST_Response {
        global $wpdb;
        $id    = (int) $request['id'];
        $table = $wpdb->prefix . 'tc_logs';

        $deleted = $wpdb->delete( $table, [ 'id' => $id ], [ '%d' ] );

        if ( ! $deleted ) {
            return new WP_REST_Response( [ 'error' => 'Log entry not found.' ], 404 );
        }

        return new WP_REST_Response( [ 'deleted' => true ] );
    }
}
