<?php
/**
 * Logger configuration and setup helpers.
 *
 * @package MailDoctor
 */

namespace MailDoctor;

use wpdb;

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

trait Logger_Config_Trait {


	/**
	 * Initialize hooks for logging lifecycle.
	 *
	 * @return void
	 */
	public static function init(): void {
		add_action( 'wp_mail_succeeded', array( __CLASS__, 'capture_success' ), 10, 1 );
		add_action( 'wp_mail_failed', array( __CLASS__, 'capture_failure' ), 10, 1 );
		add_action( 'shutdown', array( __CLASS__, 'finalize_open_logs' ), 1, 0 );
		add_action( 'shutdown', array( __CLASS__, 'maybe_prune_logs' ), 10, 0 );
		add_action( self::ARCHIVE_CRON, array( __CLASS__, 'archive_old_logs' ) );
		self::schedule_archive();
	}

	/**
	 * Return database table name with prefix.
	 *
	 * @global wpdb $wpdb WordPress DB abstraction.
	 * @return string
	 */
	public static function table_name(): string {
		global $wpdb;

		return $wpdb->prefix . 'mail_doctor_log';
	}

	/**
	 * Return archive table name.
	 *
	 * @return string
	 */
	public static function archive_table_name(): string {
		global $wpdb;

		return $wpdb->prefix . 'mail_doctor_log_archive';
	}

	/**
	 * Column list shared between active and archive tables.
	 *
	 * @return array<int, string>
	 */
	protected static function log_columns(): array {
		return array(
			'id',
			'created_at',
			'event',
			'order_id',
			'to_email',
			'subject',
			'status',
			'provider_code',
			'error',
			'duration_ms',
			'headers',
			'payload',
			'idempotency_key',
			'idempotency_bucket',
		);
	}

	/**
	 * Ensure archive table exists.
	 *
	 * @return void
	 */
	public static function ensure_archive_table(): void {
		global $wpdb;

		$table   = self::archive_table_name();
		$charset = $wpdb->get_charset_collate();

		$columns = self::log_columns();
		$schema  = "CREATE TABLE {$table} (
			id BIGINT UNSIGNED NOT NULL,
			created_at DATETIME NOT NULL,
			event VARCHAR(64) NULL,
			order_id BIGINT NULL,
			to_email TEXT NOT NULL,
			subject TEXT NOT NULL,
			status ENUM('queued','sent','failed','skipped') NOT NULL,
			provider_code VARCHAR(64) NULL,
			error TEXT NULL,
			duration_ms INT NULL,
			headers LONGTEXT NULL,
			payload LONGTEXT NULL,
			idempotency_key VARCHAR(64) NULL,
			idempotency_bucket BIGINT NULL,
			PRIMARY KEY  (id)
		) {$charset};";

		require_once ABSPATH . 'wp-admin/includes/upgrade.php';
		dbDelta( $schema );
	}

	/**
	 * Schedule archive cron hook if not already queued.
	 *
	 * @return void
	 */
	public static function schedule_archive(): void {
		if ( ! wp_next_scheduled( self::ARCHIVE_CRON ) ) {
			wp_schedule_event( time() + DAY_IN_SECONDS, 'daily', self::ARCHIVE_CRON );
		}
	}

	/**
	 * Install routine for plugin activation.
	 *
	 * @return void
	 */
	public static function install(): void {
		global $wpdb;

		$table   = self::table_name();
		$charset = $wpdb->get_charset_collate();

		$schema = "CREATE TABLE {$table} (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			created_at DATETIME NOT NULL,
			event VARCHAR(64) NULL,
			order_id BIGINT NULL,
			to_email TEXT NOT NULL,
			subject TEXT NOT NULL,
			status ENUM('queued','sent','failed','skipped') NOT NULL DEFAULT 'queued',
			provider_code VARCHAR(64) NULL,
			error TEXT NULL,
			duration_ms INT NULL,
			headers LONGTEXT NULL,
			payload LONGTEXT NULL,
			idempotency_key VARCHAR(64) NULL,
			idempotency_bucket BIGINT NULL,
			PRIMARY KEY  (id),
			KEY event (event),
			KEY order_id (order_id),
			KEY status (status),
			KEY created_at (created_at),
			KEY idempotency (idempotency_key, idempotency_bucket)
		) {$charset};";

		require_once ABSPATH . 'wp-admin/includes/upgrade.php';
		dbDelta( $schema );

		self::ensure_archive_table();
		self::schedule_archive();
	}

	/**
	 * Tear down scheduled events on plugin deactivation.
	 *
	 * @return void
	 */
	public static function deactivate(): void {
		wp_clear_scheduled_hook( self::ARCHIVE_CRON );
	}

	/**
	 * Check if a table exists.
	 *
	 * @param string $table Table name.
	 * @return bool
	 */
	protected static function table_exists( string $table ): bool {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Schema check query.
		$found = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );

		return ( $found === $table );
	}
}
