<?php
/**
 * Class Sender_Template_Manager.
 *
 * Manages sender templates CRUD operations and AJAX handlers.
 *
 * @package Inspire_Labs\Alsendo_Connect
 */

namespace Inspire_Labs\Alsendo_Connect;

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

/**
 * Sender_Template_Manager
 */
class Sender_Template_Manager {

	/**
	 * Option key for the default sender template slug.
	 */
	const DEFAULT_TEMPLATE_OPTION = 'alsendo_connect_settings_general_select_sender_template';

	/**
	 * Instance
	 *
	 * @var self|null
	 */
	private static $instance = null;

	/**
	 * Option name for storing templates.
	 *
	 * @var string
	 */
	private $option_name;

	/**
	 * Templates data.
	 *
	 * @var array
	 */
	private $data;

	/**
	 * Construct
	 */
	private function __construct() {
		$this->option_name = Plugin::APP_PREFIX . '_sender_templates';
		$this->data        = get_option( $this->option_name, array() );
		if ( is_array( $this->data ) ) {
			ksort( $this->data );
		} else {
			$this->data = array();
		}
	}

	/**
	 * Get instance
	 *
	 * @return self
	 */
	public static function get_instance(): self {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Initialize AJAX hooks.
	 *
	 * @return void
	 */
	public function init() {
		add_action( 'wp_ajax_alsendo_connect_sender_template', array( $this, 'ajax_template' ) );
		add_action( 'wp_ajax_alsendo_connect_sender_template_delete', array( $this, 'ajax_template_delete' ) );
		add_action( 'wp_ajax_alsendo_connect_sender_template_set_default', array( $this, 'ajax_set_default' ) );
	}

	/**
	 * Get the current default template slug.
	 *
	 * @return string
	 */
	public static function get_default_template_slug(): string {
		return (string) get_option( self::DEFAULT_TEMPLATE_OPTION, '' );
	}

	/**
	 * Get sender field definitions.
	 *
	 * @return array
	 */
	public static function get_sender_fields(): array {
		$fields = array(
			'is_residential'      => __( 'Address type', 'alsendo-connect' ),
			'country'             => __( 'Country', 'alsendo-connect' ),
			'company_name'        => __( 'Company name', 'alsendo-connect' ),
			'first_name'          => __( 'First Name', 'alsendo-connect' ),
			'last_name'           => __( 'Last name', 'alsendo-connect' ),
			'street'              => __( 'Street', 'alsendo-connect' ),
			'building_number'     => __( 'Building number', 'alsendo-connect' ),
			'apartment_number'    => __( 'Apartment number', 'alsendo-connect' ),
			'postal_code'         => __( 'Postal code', 'alsendo-connect' ),
			'province'            => __( 'County', 'alsendo-connect' ),
			'city'                => __( 'City', 'alsendo-connect' ),
			'contact_person'      => __( 'Contact person', 'alsendo-connect' ),
			'phone'               => __( 'Phone', 'alsendo-connect' ),
			'email'               => __( 'E-mail', 'alsendo-connect' ),
			'bank_account_number' => __( 'Bank account number', 'alsendo-connect' ),
		);

		$api_type = alsendo_connect()->get_main_settings_api();
		if ( 'ecolet' === $api_type ) {
			$fields['street']           = __( 'Street name', 'alsendo-connect' );
			$fields['building_number']  = __( 'Street number', 'alsendo-connect' );
			$fields['block']            = __( 'Block', 'alsendo-connect' );
			$fields['entrance']         = __( 'Entrance', 'alsendo-connect' );
			$fields['floor']            = __( 'Floor', 'alsendo-connect' );
			$fields['apartment_number'] = __( 'Apartment', 'alsendo-connect' );
		}

		return $fields;
	}

	/**
	 * Get all templates data.
	 *
	 * @return array
	 */
	public function get_data(): array {
		return $this->data;
	}

	/**
	 * Get value of template by ID.
	 *
	 * @param string $template_id Template ID.
	 *
	 * @return array
	 */
	public function get_value( string $template_id ): array {
		if ( isset( $this->data[ $template_id ] ) ) {
			return $this->data[ $template_id ];
		}

		return array();
	}

	/**
	 * Get templates list with optional nonce for delete actions.
	 * Merges legacy templates (from old storage) that haven't been migrated yet.
	 *
	 * @param bool $add_nonce Whether to add delete nonce to each template.
	 *
	 * @return array
	 */
	public function get_templates( bool $add_nonce = false ): array {
		$output    = array();
		$new_slugs = array();

		foreach ( $this->data as $key => $value ) {
			$data       = $this->set_data( $value );
			$data['id'] = $key;

			if ( true === $add_nonce ) {
				$data['_nonce'] = wp_create_nonce( 'alsendo_connect_ajax_sender_template_delete_' . $key );
			}

			if ( ! empty( $data['template_slug'] ) ) {
				$new_slugs[] = $data['template_slug'];
			}

			$output[] = $data;
		}

		$legacy = $this->get_legacy_templates_raw();
		if ( ! empty( $legacy ) ) {
			$next_id = $this->get_next_legacy_display_id();
			foreach ( $legacy as $slug => $old_tpl ) {
				if ( in_array( $slug, $new_slugs, true ) ) {
					continue;
				}

				$converted                 = $this->convert_legacy_template( $old_tpl, $slug );
				$converted['id']           = $next_id;
				$converted['_legacy_slug'] = $slug;

				if ( true === $add_nonce ) {
					$converted['_nonce'] = wp_create_nonce( 'alsendo_connect_ajax_sender_template_delete_' . $next_id );
				}

				$output[] = $converted;
				++$next_id;
			}
		}

		return $output;
	}

	/**
	 * Save template data.
	 *
	 * @param array $data Template data.
	 *
	 * @return void
	 */
	public function save( array $data ) {
		if ( empty( $data['id'] ) ) {
			$data['id'] = (int) $this->array_key_last( $this->data ) + 1;
		}

		if ( ! empty( $data['name'] ) ) {
			$data['template_slug'] = sanitize_title( $data['name'] );
		}

		$this->data[ $data['id'] ] = $this->set_data( $data );

		update_option( $this->option_name, $this->data );
	}

	/**
	 * Delete template by ID.
	 *
	 * @param string $id Template ID.
	 *
	 * @return void
	 */
	public function delete( string $id ) {
		if ( ! empty( $id ) ) {
			unset( $this->data[ $id ] );

			update_option( $this->option_name, $this->data );
		}
	}

	/**
	 * Process AJAX template save/update request.
	 *
	 * @return void
	 */
	public function ajax_template() {
		if ( ! empty( $_POST['template'] ) ) { // phpcs:ignore
			$data = wp_unslash( $_POST['template'] ); // phpcs:ignore

			if ( ! empty( $data['_nonce'] ) && wp_verify_nonce( sanitize_text_field( $data['_nonce'] ), 'alsendo_connect_ajax_sender_template' ) ) {
				$data['id']   = ! empty( $data['id'] ) ? absint( $data['id'] ) : 0;
				$data['name'] = ! empty( $data['name'] ) ? sanitize_text_field( $data['name'] ) : '';

				$data['is_residential']      = isset( $data['is_residential'] ) ? sanitize_text_field( $data['is_residential'] ) : '0';
				$data['country']             = ! empty( $data['country'] ) ? sanitize_text_field( $data['country'] ) : '';
				$data['company_name']        = ! empty( $data['company_name'] ) ? sanitize_text_field( $data['company_name'] ) : '';
				$data['first_name']          = ! empty( $data['first_name'] ) ? sanitize_text_field( $data['first_name'] ) : '';
				$data['last_name']           = ! empty( $data['last_name'] ) ? sanitize_text_field( $data['last_name'] ) : '';
				$data['street']              = ! empty( $data['street'] ) ? sanitize_text_field( $data['street'] ) : '';
				$data['building_number']     = ! empty( $data['building_number'] ) ? sanitize_text_field( $data['building_number'] ) : '';
				$data['block']               = ! empty( $data['block'] ) ? sanitize_text_field( $data['block'] ) : '';
				$data['entrance']            = ! empty( $data['entrance'] ) ? sanitize_text_field( $data['entrance'] ) : '';
				$data['floor']               = ! empty( $data['floor'] ) ? sanitize_text_field( $data['floor'] ) : '';
				$data['apartment_number']    = ! empty( $data['apartment_number'] ) ? sanitize_text_field( $data['apartment_number'] ) : '';
				$data['postal_code']         = ! empty( $data['postal_code'] ) ? sanitize_text_field( $data['postal_code'] ) : '';
				$data['province']            = ! empty( $data['province'] ) ? sanitize_text_field( $data['province'] ) : '';
				$data['city']                = ! empty( $data['city'] ) ? sanitize_text_field( $data['city'] ) : '';
				$data['contact_person']      = ! empty( $data['contact_person'] ) ? sanitize_text_field( $data['contact_person'] ) : '';
				$data['phone']               = ! empty( $data['phone'] ) ? sanitize_text_field( $data['phone'] ) : '';
				$data['email']               = ! empty( $data['email'] ) ? sanitize_email( $data['email'] ) : '';
				$data['bank_account_number'] = ! empty( $data['bank_account_number'] ) ? sanitize_text_field( $data['bank_account_number'] ) : '';

				$set_as_default = ! empty( $data['set_as_default'] ) && '1' === $data['set_as_default'];

				if ( 0 > $data['id'] ) {
					$data['id'] = 0;
				}
				if ( empty( $data['name'] ) ) {
					wp_send_json(
						array(
							array(
								'type'    => 'error',
								'message' => __( 'Field "Name" is required.', 'alsendo-connect' ),
							),
						),
						\WP_Http::UNPROCESSABLE_ENTITY
					);

					return;
				}

				if ( $this->name_exists( $data['name'], $data['id'] ) ) {
					wp_send_json(
						array(
							array(
								'type'    => 'error',
								'message' => __( 'A template with this name already exists. Please choose a different name.', 'alsendo-connect' ),
							),
						),
						\WP_Http::UNPROCESSABLE_ENTITY
					);

					return;
				}

				$legacy_slug = ! empty( $data['_legacy_slug'] ) ? sanitize_text_field( $data['_legacy_slug'] ) : '';

				if ( ! empty( $legacy_slug ) ) {
					$data['id'] = 0;
				}

				$this->save( $data );

				if ( ! empty( $legacy_slug ) ) {
					$this->remove_legacy_template( $legacy_slug );
				}

				if ( $set_as_default ) {
					update_option( self::DEFAULT_TEMPLATE_OPTION, sanitize_title( $data['name'] ) );
				}

				wp_send_json( array(), \WP_Http::OK );

				return;
			}
		}

		wp_send_json( '', \WP_Http::BAD_REQUEST );
	}

	/**
	 * Process AJAX template delete request.
	 *
	 * @return void
	 */
	public function ajax_template_delete() {
		if ( ! empty( $_POST['template_delete'] ) ) { // phpcs:ignore
			$data = wp_unslash( $_POST['template_delete'] ); // phpcs:ignore
			$id   = ! empty( $data['id'] ) ? absint( $data['id'] ) : 0;

			if ( ! empty( $data['_nonce'] ) && wp_verify_nonce( sanitize_text_field( $data['_nonce'] ), 'alsendo_connect_ajax_sender_template_delete_' . $id ) ) {
				$legacy_slug = ! empty( $data['_legacy_slug'] ) ? sanitize_text_field( $data['_legacy_slug'] ) : '';

				$this->delete( $id );

				if ( ! empty( $legacy_slug ) ) {
					$this->remove_legacy_template( $legacy_slug );
				}

				wp_send_json( array(), \WP_Http::NO_CONTENT );

				return;
			}
		}

		wp_send_json( '', \WP_Http::BAD_REQUEST );
	}

	/**
	 * Process AJAX set default template request.
	 *
	 * @return void
	 */
	public function ajax_set_default() {
		if ( ! empty( $_POST['_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_nonce'] ) ), 'alsendo_connect_ajax_set_default_sender_template' ) ) {
			$template_slug = ! empty( $_POST['template_slug'] ) ? sanitize_text_field( wp_unslash( $_POST['template_slug'] ) ) : '';

			if ( ! empty( $template_slug ) ) {
				update_option( self::DEFAULT_TEMPLATE_OPTION, $template_slug );
				wp_send_json( array( 'slug' => $template_slug ), \WP_Http::OK );

				return;
			}
		}

		wp_send_json( '', \WP_Http::BAD_REQUEST );
	}

	/**
	 * Get legacy option name used by Sender_Settings_Templates_Helper.
	 *
	 * @return string
	 */
	private function get_legacy_option_name(): string {
		return Plugin::APP_PREFIX . 'sender_opts_templates';
	}

	/**
	 * Read raw legacy templates from old storage.
	 *
	 * @return array
	 */
	private function get_legacy_templates_raw(): array {
		$templates = get_option( $this->get_legacy_option_name(), array() );

		return is_array( $templates ) ? $templates : array();
	}

	/**
	 * Convert a single legacy template (old format) to new format.
	 *
	 * Legacy format stores options with full prefixed keys like
	 * 'alsendo_connect_settings_general_sender_company_name'.
	 *
	 * @param array  $old_tpl Legacy template data with 'name' and 'options'.
	 * @param string $slug    Legacy template slug (array key).
	 *
	 * @return array
	 */
	private function convert_legacy_template( array $old_tpl, string $slug ): array {
		$prefix  = 'alsendo_connect_settings_general_sender_';
		$options = isset( $old_tpl['options'] ) ? $old_tpl['options'] : array();

		return array(
			'name'                => $old_tpl['name'] ?? '',
			'template_slug'       => $slug,
			'is_residential'      => $options[ $prefix . 'is_residential' ] ?? '0',
			'country'             => $options[ $prefix . 'country' ] ?? '',
			'company_name'        => $options[ $prefix . 'company_name' ] ?? '',
			'first_name'          => $options[ $prefix . 'first_name' ] ?? '',
			'last_name'           => $options[ $prefix . 'last_name' ] ?? '',
			'street'              => $options[ $prefix . 'street' ] ?? '',
			'building_number'     => $options[ $prefix . 'building_number' ] ?? '',
			'block'               => $options[ $prefix . 'block' ] ?? '',
			'entrance'            => $options[ $prefix . 'entrance' ] ?? '',
			'floor'               => $options[ $prefix . 'floor' ] ?? '',
			'apartment_number'    => $options[ $prefix . 'apartment_number' ] ?? '',
			'postal_code'         => $options[ $prefix . 'postal_code' ] ?? '',
			'province'            => $options[ $prefix . 'province' ] ?? '',
			'city'                => $options[ $prefix . 'city' ] ?? '',
			'contact_person'      => $options[ $prefix . 'contact_person' ] ?? '',
			'phone'               => $options[ $prefix . 'phone' ] ?? '',
			'email'               => $options[ $prefix . 'email' ] ?? '',
			'bank_account_number' => $options[ $prefix . 'bank_account_number' ] ?? '',
		);
	}

	/**
	 * Generate starting ID for legacy templates display (avoids collision with real IDs).
	 *
	 * @return int
	 */
	private function get_next_legacy_display_id(): int {
		$max = 0;
		foreach ( $this->data as $key => $value ) {
			if ( (int) $key > $max ) {
				$max = (int) $key;
			}
		}

		return max( $max + 1, 90000 );
	}

	/**
	 * Remove a single template from legacy storage by slug.
	 *
	 * @param string $slug Template slug.
	 *
	 * @return void
	 */
	private function remove_legacy_template( string $slug ): void {
		$option_name = $this->get_legacy_option_name();
		$templates   = get_option( $option_name, array() );

		if ( is_array( $templates ) && isset( $templates[ $slug ] ) ) {
			unset( $templates[ $slug ] );
			update_option( $option_name, $templates );
		}
	}

	/**
	 * Check if a template with the given name already exists.
	 *
	 * @param string $name        Template name to check.
	 * @param int    $exclude_id  Template ID to exclude from the check (for edits).
	 *
	 * @return bool
	 */
	private function name_exists( string $name, int $exclude_id = 0 ): bool {
		$name_lower = mb_strtolower( trim( $name ) );
		foreach ( $this->data as $key => $value ) {
			if ( (int) $key === $exclude_id ) {
				continue;
			}
			$existing_name = isset( $value['name'] ) ? mb_strtolower( trim( $value['name'] ) ) : '';
			if ( $existing_name === $name_lower ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Gets the last key of an array.
	 *
	 * @param mixed $arr_data An array.
	 *
	 * @return mixed
	 */
	private function array_key_last( $arr_data ) {
		if ( ! is_array( $arr_data ) || empty( $arr_data ) ) {
			return null;
		}

		return array_keys( $arr_data )[ count( $arr_data ) - 1 ];
	}

	/**
	 * Normalize template data structure.
	 *
	 * @param array $value Raw values.
	 *
	 * @return array
	 */
	private function set_data( array $value ): array {
		$data = array(
			'name'                => null,
			'template_slug'       => null,
			'is_residential'      => '0',
			'country'             => null,
			'company_name'        => null,
			'first_name'          => null,
			'last_name'           => null,
			'street'              => null,
			'building_number'     => null,
			'block'               => null,
			'entrance'            => null,
			'floor'               => null,
			'apartment_number'    => null,
			'postal_code'         => null,
			'province'            => null,
			'city'                => null,
			'contact_person'      => null,
			'phone'               => null,
			'email'               => null,
			'bank_account_number' => null,
		);
		foreach ( $data as $key => $v ) {
			if ( isset( $value[ $key ] ) ) {
				$data[ $key ] = $value[ $key ];
			}
		}

		return $data;
	}
}
