<?php
/**
 * NotificationLogTable — standalone class file.
 *
 * @package UltraguardPro\modules\notifications\db
 */

namespace UltraguardPro\modules\notifications\db;

use UltraguardPro\db\BaseTable;

if ( ! defined( 'ABSPATH' ) ) { exit; }

namespace UltraguardPro\modules\notifications\db;

use UltraguardPro\db\BaseTable;

if ( ! defined( 'ABSPATH' ) ) { exit; }

class NotificationLogTable extends BaseTable {

    protected $table_name  = 'ultraguard_notification_log';
    protected $cache_group = 'ultraguard_notification_log';

    // ── BaseTable contract ─────────────────────────────────────────────────────

    public function get_defaults(): array {
        return [
            'id'            => 0,
            'event_type'    => '',
            'channel'       => 'email',
            'recipient'     => '',
            'subject'       => '',
            'message'       => '',
            'status'        => 'sent',
            'rule_id'       => null,
            'error_message' => null,
            'context_json'  => null,
            'sent_at'       => null,
            'created_at'    => '',
        ];
    }

    protected function validate_data( $data ) {
        if ( empty( $data['event_type'] ) || empty( $data['recipient'] ) ) { return false; }

        $valid_channels = [ 'email', 'admin_notice', 'webhook', 'slack', 'sms' ];
        if ( isset( $data['channel'] ) && ! in_array( $data['channel'], $valid_channels, true ) ) {
            $data['channel'] = 'email';
        }

        $valid_statuses = [ 'sent', 'failed', 'queued', 'skipped' ];
        if ( isset( $data['status'] ) && ! in_array( $data['status'], $valid_statuses, true ) ) {
            $data['status'] = 'queued';
        }

        return $data;
    }

    protected function sanitize_data( $data ): array {
        $out = [];
        foreach ( $data as $k => $v ) {
            $out[ $k ] = match ( $k ) {
                'message',
                'error_message' => is_null( $v ) ? null : wp_kses_post( (string) $v ),
                'context_json'  => is_null( $v ) ? null
                                 : ( is_array( $v ) ? wp_json_encode( $v ) : sanitize_textarea_field( (string) $v ) ),
                'rule_id'       => is_null( $v ) ? null : absint( $v ),
                default         => is_string( $v ) ? sanitize_text_field( $v ) : $v,
            };
        }
        return $out;
    }

    protected function get_searchable_fields(): array {
        return [ 'event_type', 'recipient', 'subject', 'channel', 'status' ];
    }

    // ── Domain methods ─────────────────────────────────────────────────────────

    /**
     * Record a dispatched notification.
     *
     * @param  string      $event_type
     * @param  string      $channel
     * @param  string      $recipient
     * @param  string      $subject
     * @param  string      $message
     * @param  string      $status
     * @param  int|null    $rule_id
     * @param  string|null $error
     * @param  array       $context     Stored as JSON for audit trail.
     * @return int|false
     */
    public function record(
        string  $event_type,
        string  $channel,
        string  $recipient,
        string  $subject,
        string  $message,
        string  $status    = 'sent',
        ?int    $rule_id   = null,
        ?string $error     = null,
        array   $context   = []
    ): int|false {
        return $this->insert( [
            'event_type'    => $event_type,
            'channel'       => $channel,
            'recipient'     => $recipient,
            'subject'       => $subject,
            'message'       => $message,
            'status'        => $status,
            'rule_id'       => $rule_id,
            'error_message' => $error,
            'context_json'  => ! empty( $context ) ? $context : null,
            'sent_at'       => $status === 'sent' ? current_time( 'mysql', true ) : null,
        ] );
    }

    /**
     * Get failed notifications (for retry / admin display).
     *
     * @param int $limit
     * @return array
     */
    public function get_failed( int $limit = 100 ): array {
        return $this->get_by( [ 'status' => 'failed' ], $limit, 'created_at', 'DESC' );
    }

    /**
     * Flat stat snapshot for dashboard cards.
     *
     * @return array{total_sent_24h:int, total_failed_24h:int, total_sent:int, total_failed:int, delivery_rate:float}
     */
    public function get_stats_summary(): array {
        $h24   = gmdate( 'Y-m-d H:i:s', strtotime( '-24 hours' ) );
        $sent  = $this->count( [ 'status' => 'sent'   ] );
        $failed= $this->count( [ 'status' => 'failed' ] );

        return [
            'total_sent_24h'   => $this->count( [ 'status' => 'sent',   'sent_at >=' => $h24 ] ),
            'total_failed_24h' => $this->count( [ 'status' => 'failed', 'created_at >=' => $h24 ] ),
            'total_sent'       => $sent,
            'total_failed'     => $failed,
            'delivery_rate'    => ( $sent + $failed ) > 0
                ? round( $sent / ( $sent + $failed ) * 100, 1 )
                : 100.0,
        ];
    }

    /**
     * Mark a batch of log entries as retried.
     *
     * @param  array $ids
     * @return int
     */
    public function mark_retried( array $ids ): int {
        $count = 0;
        foreach ( array_map( 'absint', $ids ) as $id ) {
            if ( $id && $this->update( $id, [ 'status' => 'queued' ] ) ) { $count++; }
        }
        return $count;
    }
}


/**
 * NotificationRulesTable — User-defined notification trigger rules.
 *
 * @package UltraguardPro\modules\notifications\db
 * @since   6.5.0
 */
