<?php

namespace Limb_Chatbot\Includes\Services\Notifications;

use wpdb;

/**
 * Persists notification delivery log (audit) to lbaic_notification_log.
 *
 * Used optionally by Notification_Service to record sent/failed notifications.
 *
 * @package Limb_Chatbot\Includes\Services\Notifications
 * @since 1.0.15
 */
class Notification_Log_Repository {

	/**
	 * Table name (without prefix).
	 */
	const TABLE_NAME = 'lbaic_notification_log';

	/**
	 * @var wpdb
	 * @since 1.0.15
	 */
	private wpdb $wpdb;

	/**
	 * Constructor.
	 *
	 * @param  wpdb|null  $wpdb  Optional wpdb instance.
	 *
	 * @since 1.0.15
	 */
	public function __construct( ?wpdb $wpdb = null ) {
		$this->wpdb = $wpdb ?? $GLOBALS['wpdb'];
	}

	/**
	 * Insert a pending notification row (during queueing). Call update_status when processed.
	 *
	 * @param  int  $chatbot_user_id  Chatbot user ID.
	 * @param  string  $type_key  Notification type key.
	 * @param  string  $channel  Channel key.
	 *
	 * @return int|null Inserted row ID, or null on failure.
	 * @since 1.0.15
	 */
	public function insert_pending( int $chatbot_user_id, string $type_key, string $channel ): ?int {
		$table = $this->wpdb->prefix . self::TABLE_NAME;

		$result = $this->wpdb->insert(
			$table,
			[
				'chatbot_user_id' => $chatbot_user_id,
				'type_key'        => $type_key,
				'channel'         => $channel,
				'status'          => 'pending',
				'sent_at'         => null,
			],
			[ '%d', '%s', '%s', '%s', '%s' ]
		);

		if ( $result === false ) {
			return null;
		}

		return (int) $this->wpdb->insert_id;
	}

	/**
	 * Update a notification log row to completed/failed (during processing).
	 *
	 * @param  int  $id  Log row ID.
	 * @param  string  $status  'sent' or 'failed'.
	 * @param  string|null  $sent_at  Timestamp when sent; null uses current_time.
	 * @param  string|null  $fail_reason  Reason for failure when status is 'failed'.
	 * @param  string|null  $content_type  Content type (e.g. 'text/plain', 'text/html').
	 * @param  string|null  $content  Body content that was sent or attempted.
	 *
	 * @return bool True if updated.
	 * @since 1.0.15
	 */
	public function update_status( int $id, string $status, ?string $sent_at = null, ?string $fail_reason = null, ?string $content_type = null, ?string $content = null ): bool {
		$table = $this->wpdb->prefix . self::TABLE_NAME;
		$sent  = $sent_at ?? current_time( 'mysql' );

		$data   = [ 'status' => $status, 'sent_at' => $sent ];
		$format = [ '%s', '%s' ];

		if ( $status === 'failed' && $fail_reason !== null ) {
			$data['fail_reason'] = $fail_reason;
			$format[]            = '%s';
		}
		if ( $content_type !== null ) {
			$data['content_type'] = $content_type;
			$format[]             = '%s';
		}
		if ( $content !== null ) {
			$data['content'] = $content;
			$format[]        = '%s';
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$result = $this->wpdb->update(
			$table,
			$data,
			[ 'id' => $id ],
			$format,
			[ '%d' ]
		);

		return $result !== false;
	}

	/**
	 * Log a notification delivery attempt (legacy: when no pending row exists, e.g. old queue items).
	 *
	 * @param  int  $chatbot_user_id  Chatbot user ID.
	 * @param  string  $type_key  Notification type key.
	 * @param  string  $channel  Channel key.
	 * @param  string  $status  'sent' or 'failed'.
	 * @param  string|null  $fail_reason  Reason for failure when status is 'failed'.
	 * @param  string|null  $content_type  Content type (e.g. 'text/plain', 'text/html').
	 * @param  string|null  $content  Body content that was sent or attempted.
	 *
	 * @return bool True if inserted.
	 * @since 1.0.15
	 */
	public function log( int $chatbot_user_id, string $type_key, string $channel, string $status = 'sent', ?string $fail_reason = null, ?string $content_type = null, ?string $content = null ): bool {
		$table = $this->wpdb->prefix . self::TABLE_NAME;

		$data = [
			'chatbot_user_id' => $chatbot_user_id,
			'type_key'        => $type_key,
			'channel'         => $channel,
			'status'          => $status,
			'sent_at'         => current_time( 'mysql' ),
		];
		$format = [ '%d', '%s', '%s', '%s', '%s' ];

		if ( $status === 'failed' && $fail_reason !== null ) {
			$data['fail_reason'] = $fail_reason;
			$format[]            = '%s';
		}
		if ( $content_type !== null ) {
			$data['content_type'] = $content_type;
			$format[]             = '%s';
		}
		if ( $content !== null ) {
			$data['content'] = $content;
			$format[]        = '%s';
		}

		$result = $this->wpdb->insert( $table, $data, $format );

		return $result !== false;
	}
}
