<?php

namespace Limb_Chatbot\Includes\Services\Notifications\Types;

use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Chatbot_User;
use Limb_Chatbot\Includes\Data_Objects\Setting;
use Limb_Chatbot\Includes\Interfaces\Notification_Type_Interface;
use Limb_Chatbot\Includes\Services\Notifications\Notification_Envelope;
use Limb_Chatbot\Includes\Services\Conversation_Formatter;

/**
 * Base implementation for notification types.
 *
 * Subclasses define key, target roles, channels, and build_envelope() for dynamic content.
 *
 * @package Limb_Chatbot\Includes\Services\Notifications\Types
 * @since 1.0.15
 */
abstract class Abstract_Notification_Type implements Notification_Type_Interface {

	/**
	 * Default channels for this type (override in subclass if needed).
	 *
	 * @var string[]
	 * @since 1.0.15
	 */
	protected array $channels = [ 'email' ];

	/**
	 * Default target roles (override in subclass).
	 *
	 * @return string[]
	 * @since 1.0.15
	 */
	abstract public function get_target_roles(): array;

	/**
	 * @inheritDoc
	 */
	public function get_channels(): array {
		return $this->channels;
	}

	/**
	 * Default: queued (not instant). Override in subclass for instant notifications.
	 *
	 * @return bool
	 * @since 1.0.15
	 */
	public function is_instant(): bool {
		return false;
	}

	/**
	 * Create an envelope instance (helper for subclasses).
	 *
	 * @param  string  $channel_key  Channel key.
	 * @param  string  $subject  Subject.
	 * @param  string  $body  Body.
	 * @param  array  $payload  Optional payload.
	 * @param  string  $content_type  Content type (e.g. 'text/plain', 'text/html').
	 *
	 * @return Notification_Envelope
	 * @since 1.0.15
	 */
	protected function create_envelope( string $channel_key, string $subject, string $body, array $payload = [], string $content_type = 'text/plain' ): Notification_Envelope {
		return new Notification_Envelope(
			$this->get_key(),
			$channel_key,
			$subject,
			$body,
			$payload,
			$content_type
		);
	}

	/**
	 * Build channel payload needed by channels (email: custom recipients, etc).
	 *
	 * @param array $context_payload
	 * @return array
	 * @since 2.0.0
	 */
	protected function build_channel_payload( array $context_payload ): array {
		$payload = [];
		if ( isset( $context_payload['custom_emails'] ) && is_array( $context_payload['custom_emails'] ) ) {
			$payload['custom_emails'] = $context_payload['custom_emails'];
		}

		if ( isset( $context_payload['to_emails'] ) && is_array( $context_payload['to_emails'] ) ) {
			$payload['to_emails'] = $context_payload['to_emails'];
		}

		if ( array_key_exists( 'send_recipient_email', $context_payload ) ) {
			$payload['send_recipient_email'] = (bool) $context_payload['send_recipient_email'];
		}

		// Keep custom headers supported by older envelope implementations.
		if ( isset( $context_payload['headers'] ) && is_array( $context_payload['headers'] ) ) {
			$payload['headers'] = $context_payload['headers'];
		}

		return $payload;
	}

	/**
	 * @return array{subject:string,body:string}
	 * @since 2.0.0
	 */
	protected function get_email_template_config(): array {
		// Back-compat + your naming example support:
		// - primary key: `lbaic.plugin.notifications`
		// - alias key:   `lbaic.plugin.notification_types`
		$setting = Setting::find( 'lbaic.plugin.notification_types' );
		$value   = $setting instanceof Setting ? $setting->get_value() : null;
		if ( ! is_array( $value ) ) {
			$setting = Setting::find( 'lbaic.plugin.notifications' );
			$value   = $setting instanceof Setting ? $setting->get_value() : null;
		}
		$value   = is_array( $value ) ? $value : [];

		$type_key = $this->get_key();
		if ( empty( $value[ $type_key ]['email_template'] ) || ! is_array( $value[ $type_key ]['email_template'] ) ) {
			return [
				'subject' => '',
				'body'    => '',
			];
		}

		$template = $value[ $type_key ]['email_template'];

		return [
			'subject' => (string) ( $template['subject'] ?? '' ),
			'body'    => (string) ( $template['body'] ?? '' ),
		];
	}

	/**
	 * Render template variables into a template string.
	 *
	 * Supported variables:
	 * - {{visitor_ip}}
	 * - {{chat_id}}
	 * - {{timestamp}}
	 * - {{site_name}}
	 * - {{chat_summary}}
	 *
	 * @param string $template
	 * @param array{visitor_ip:string,chat_id:string,timestamp:string,site_name:string,chat_summary:string} $vars
	 * @return string
	 * @since 2.0.0
	 */
	protected function apply_template_variables( string $template, array $vars ): string {
		$chat_summary = $vars['chat_summary'] ?? '';
		$chat_summary_html = '';
		if ( is_string( $chat_summary ) && $chat_summary !== '' ) {
			// Handle both `\n` and Windows-style `\r\n`.
			$lines = preg_split( "/\R/", $chat_summary );
			if ( ! is_array( $lines ) ) {
				$lines = [];
			}
			$lines = array_map( function ( $line ) {
				return esc_html( $line );
			}, $lines );
			$chat_summary_html = implode( '<br>', $lines );
		} else {
			$chat_summary_html = esc_html( '[no conversation history]' );
		}

		$replacements = [
			'{{visitor_ip}}'   => esc_html( (string) ( $vars['visitor_ip'] ?? '' ) ),
			'{{chat_id}}'       => esc_html( (string) ( $vars['chat_id'] ?? '' ) ),
			'{{timestamp}}'    => esc_html( (string) ( $vars['timestamp'] ?? '' ) ),
			'{{site_name}}'    => esc_html( (string) ( $vars['site_name'] ?? '' ) ),
			'{{chat_summary}}' => $chat_summary_html,
		];

		return str_replace( array_keys( $replacements ), array_values( $replacements ), $template );
	}

	/**
	 * Build template variables for a given chat UUID.
	 *
	 * @param string|null $chat_uuid
	 * @return array{visitor_ip:string,chat_id:string,timestamp:string,site_name:string,chat_summary:string}
	 * @since 2.0.0
	 */
	protected function build_template_vars( ?string $chat_uuid ): array {
		$timestamp = current_time( 'mysql', true );
		$site_name = (string) get_bloginfo( 'name' );

		$visitor_ip = '';
		$chat_id = '';
		$chat_summary = '';

		if ( ! empty( $chat_uuid ) ) {
			$chat = Chat::where( [ 'uuid' => $chat_uuid ] )->first();
			if ( $chat instanceof Chat ) {
				$chat_id = (string) $chat->get_id();
				$visitor = $chat->user();
				if ( $visitor instanceof Chatbot_User ) {
					$visitor_ip = (string) ( $visitor->get_ip() ?? '' );
				}

				$chat_summary = ( new Conversation_Formatter() )->format_chat_conversation( $chat, 10 );
			}
		}

		return [
			'visitor_ip'   => $visitor_ip,
			'chat_id'       => (string) $chat_id,
			'timestamp'    => $timestamp,
			'site_name'    => $site_name,
			'chat_summary' => $chat_summary,
		];
	}

	/**
	 * Append a short entity identifier to email subjects.
	 *
	 * Helps mailbox clients avoid collapsing separate events into one thread.
	 *
	 * @param string $subject Base subject.
	 * @param string $entity_id Entity identifier value.
	 * @return string
	 * @since 2.1.0
	 */
	protected function append_subject_identifier( string $subject, string $entity_id ): string {
		$entity_id = trim( (string) $entity_id );
		if ( '' === $entity_id ) {
			return $subject;
		}

		return sprintf( '%s [#%s]', $subject, $entity_id );
	}
}
