<?php
/**
 * Promotional banner shown on the Magic Links list page to free users.
 *
 * Free-only, one-shot dismissible (per user), time-boxed campaign.
 * Everything user-facing goes through filters so a future release can
 * change copy or dates without a code change.
 *
 * @package KaizenCoders\MagicLink\Admin\Promotions
 */

namespace KaizenCoders\MagicLink\Admin\Promotions;

use KaizenCoders\MagicLink\Helper;

class PromoBanner {

	const USER_META_DISMISSED = '_kc_ml_promo_dismissed_50off';
	const AJAX_ACTION         = 'kc_ml_dismiss_promo';
	const NONCE_ACTION        = 'kc_ml_dismiss_promo';
	const SCREEN_ID           = 'magic-link_page_magic-link-links';

	public function init() {
		// admin_notices fires INSIDE #wpbody-content > .wrap, so the banner
		// inherits the same left/right margins the WP admin content uses to
		// clear the sidebar. Rendering it on `init` (or any other hook that
		// runs before the admin template opens the .wrap container) makes
		// the browser paint it at viewport (0, 0), overlapping the sidebar.
		add_action( 'admin_notices', array( $this, 'maybe_render_magic_link_promo' ) );
		add_action( 'wp_ajax_' . self::AJAX_ACTION, array( $this, 'handle_dismiss' ) );
	}

	// ------------------------------------------------------------------
	// Configuration (all filterable)
	// ------------------------------------------------------------------

	public static function config() {
		return array(
			'headline' => (string) apply_filters(
				'kc_ml_promo_headline',
				__( '🎉 Save 50% on Magic Link PRO', 'magic-link' )
			),
			'subhead'  => (string) apply_filters(
				'kc_ml_promo_subhead',
				__( 'Yearly and lifetime plans — limited-time offer.', 'magic-link' )
			),
			'coupon'   => (string) apply_filters( 'kc_ml_promo_coupon', 'MAGIC50' ),
			'start'    => (string) apply_filters( 'kc_ml_promo_start', '2026-07-01' ),
			'end'      => (string) apply_filters( 'kc_ml_promo_end',   '2026-09-30' ),
			'cta_url'  => 'https://kaizencoders.com/magic-link/#pricing?utm_source=magic-link-in-app&utm_medium=banner&utm_campaign=july-2026-offer',
			'cta_text' => (string) apply_filters(
				'kc_ml_promo_cta_text',
				__( 'Upgrade & Save 50%', 'magic-link' )
			),
			'compare_url'  => (string) apply_filters(
				'kc_ml_promo_compare_url',
				'https://kaizencoders.com/magic-link/#pricing?utm_source=magic-link-in-app&utm_medium=banner&utm_campaign=july-2026-offer'
			),
			'compare_text' => (string) apply_filters(
				'kc_ml_promo_compare_text',
				__( 'Compare plans', 'magic-link' )
			),
		);
	}

	private static function cta_url() {
		$base = function_exists( 'magic_link_fs' )
			? (string) magic_link_fs()->get_upgrade_url()
			: 'https://kaizencoders.com/magic-link/';

		$default = add_query_arg(
			array(
				'utm_source'   => 'magic-link-in-app',
				'utm_medium'   => 'banner',
				'utm_campaign' => 'july-2026-offer',
			),
			$base
		);

		return (string) apply_filters( 'kc_ml_promo_cta_url', $default );
	}

	// ------------------------------------------------------------------
	// Show-logic predicates (unit-tested)
	// ------------------------------------------------------------------

	/**
	 * True when the banner should render right now for the given inputs.
	 *
	 * @param  array $context is_pro, screen_id, now (unix ts), user_dismissed,
	 *                        start (ISO date), end (ISO date).
	 *
	 * @return bool
	 */
	public static function should_show( $context ) {
		$context = (array) $context;

		if ( ! empty( $context['is_pro'] ) ) {
			return false;
		}

        if ( ! Helper::is_plugin_admin_screen() ) {
            return false;
        }

		if ( ! empty( $context['user_dismissed'] ) ) {
			return false;
		}
		if ( ! self::is_in_window(
			isset( $context['now'] ) ? (int) $context['now'] : time(),
			isset( $context['start'] ) ? (string) $context['start'] : '',
			isset( $context['end'] ) ? (string) $context['end'] : ''
		) ) {
			return false;
		}
		return true;
	}

	/**
	 * True when $now falls inside [$start, $end] inclusive. Empty
	 * boundaries mean "no bound in that direction".
	 *
	 * @param  int    $now   Unix timestamp.
	 * @param  string $start ISO date (YYYY-MM-DD) or empty.
	 * @param  string $end   ISO date (YYYY-MM-DD) or empty.
	 *
	 * @return bool
	 */
	public static function is_in_window( $now, $start, $end ) {
		$now = (int) $now;
		if ( '' !== $start ) {
			$start_ts = strtotime( $start . ' 00:00:00 UTC' );
			if ( false !== $start_ts && $now < $start_ts ) {
				return false;
			}
		}
		if ( '' !== $end ) {
			$end_ts = strtotime( $end . ' 23:59:59 UTC' );
			if ( false !== $end_ts && $now > $end_ts ) {
				return false;
			}
		}
		return true;
	}

	// ------------------------------------------------------------------
	// Render
	// ------------------------------------------------------------------

	public function maybe_render_magic_link_promo() {
		if ( ! self::should_show( array(
			'is_pro'         => function_exists( 'KC_ML' ) && KC_ML()->is_pro(),
			'user_dismissed' => self::user_dismissed(),
			'now'            => time(),
			'start'          => (string) apply_filters( 'kc_ml_promo_start', '2026-07-01' ),
			'end'            => (string) apply_filters( 'kc_ml_promo_end',   '2026-16-30' ),
		) ) ) {
			return;
		}


		$cfg   = self::config();
		$nonce = wp_create_nonce( self::NONCE_ACTION );
		?>
		<div id="kc-ml-promo-banner" class="kc-ml-promo-banner" role="region" aria-label="<?php esc_attr_e( 'Magic Link promotion', 'magic-link' ); ?>">
			<div class="kc-ml-promo-inner">
				<div class="kc-ml-promo-copy">
					<div class="kc-ml-promo-headline"><?php echo esc_html( $cfg['headline'] ); ?></div>
					<div class="kc-ml-promo-subhead"><?php echo esc_html( $cfg['subhead'] ); ?></div>
				</div>

				<div class="kc-ml-promo-coupon">
					<span class="kc-ml-promo-coupon-label"><?php esc_html_e( 'Coupon', 'magic-link' ); ?></span>
					<span class="kc-ml-promo-coupon-code" id="kc-ml-promo-coupon-code"><?php echo esc_html( $cfg['coupon'] ); ?></span>
					<button type="button" class="kc-ml-copy-link kc-ml-promo-copy-btn"
					        data-magic-url="<?php echo esc_attr( $cfg['coupon'] ); ?>"
					        aria-label="<?php esc_attr_e( 'Copy coupon code', 'magic-link' ); ?>">
						<?php esc_html_e( 'Copy', 'magic-link' ); ?>
					</button>
				</div>

				<div class="kc-ml-promo-actions">
					<a class="kc-ml-promo-cta" href="<?php echo esc_url( $cfg['cta_url'] ); ?>" target="_blank" rel="noopener">
						<?php echo esc_html( $cfg['cta_text'] ); ?> <span aria-hidden="true">→</span>
					</a>
					<a class="kc-ml-promo-secondary" href="<?php echo esc_url( $cfg['compare_url'] ); ?>" target="_blank" rel="noopener">
						<?php echo esc_html( $cfg['compare_text'] ); ?>
					</a>
				</div>

				<button type="button" class="kc-ml-promo-dismiss" id="kc-ml-promo-dismiss"
				        aria-label="<?php esc_attr_e( 'Dismiss this promotion', 'magic-link' ); ?>"
				        data-nonce="<?php echo esc_attr( $nonce ); ?>">
					×
				</button>
			</div>
		</div>

		<style>
			.kc-ml-promo-banner {
				box-sizing: border-box;
				background: linear-gradient(90deg, #4f46e5 0%, #7c3aed 100%);
				color: #fff;
				border-radius: 8px;
				box-shadow: 0 4px 12px rgba(79, 70, 229, .18);
				/* Sit inside .wrap; WP already provides ~20px left padding via
				   .wrap so a small margin here is enough. `max-width` guards
				   against edge cases where the notice slot is unusually wide. */
				margin: 16px 20px 20px 0;
				padding: 18px 20px;
				max-width: 100%;
				position: relative;
				overflow: hidden;
			}
			.kc-ml-promo-inner {
				display: flex;
				align-items: center;
				gap: 24px;
				flex-wrap: wrap;
			}
			.kc-ml-promo-copy { flex: 1 1 260px; min-width: 240px; }
			.kc-ml-promo-headline { font-size: 18px; font-weight: 700; line-height: 1.3; }
			.kc-ml-promo-subhead  { font-size: 13px; opacity: .9; margin-top: 4px; }
			.kc-ml-promo-coupon {
				display: inline-flex;
				align-items: center;
				gap: 8px;
				background: rgba(255,255,255,.14);
				border: 1px dashed rgba(255,255,255,.5);
				border-radius: 6px;
				padding: 8px 12px;
			}
			.kc-ml-promo-coupon-label {
				font-size: 11px; letter-spacing: .04em; text-transform: uppercase; opacity: .8;
			}
			.kc-ml-promo-coupon-code {
				font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
				font-size: 14px; font-weight: 700; letter-spacing: .04em;
			}
			.kc-ml-promo-copy-btn {
				background: rgba(255,255,255,.22) !important;
				border: 0 !important;
				color: #fff !important;
				font-size: 12px !important;
				padding: 4px 10px !important;
				border-radius: 4px !important;
				cursor: pointer !important;
				box-shadow: none !important;
			}
			.kc-ml-promo-copy-btn:hover { background: rgba(255,255,255,.32) !important; }
			.kc-ml-promo-actions { display: flex; align-items: center; gap: 16px; }
			.kc-ml-promo-cta {
				background: #ffffff;
				color: #4f46e5;
				font-weight: 700;
				text-decoration: none;
				padding: 10px 18px;
				border-radius: 6px;
				transition: transform .12s ease, box-shadow .12s ease;
			}
			.kc-ml-promo-cta:hover {
				transform: translateY(-1px);
				box-shadow: 0 4px 10px rgba(0,0,0,.15);
				color: #4f46e5;
			}
			.kc-ml-promo-secondary {
				color: rgba(255,255,255,.92);
				text-decoration: underline;
				font-size: 13px;
			}
			.kc-ml-promo-secondary:hover { color: #fff; }
			.kc-ml-promo-dismiss {
				position: absolute;
				top: 8px; right: 10px;
				background: transparent;
				border: 0;
				color: rgba(255,255,255,.85);
				font-size: 22px;
				line-height: 1;
				cursor: pointer;
				padding: 4px 8px;
				border-radius: 4px;
			}
			.kc-ml-promo-dismiss:hover { background: rgba(255,255,255,.15); color: #fff; }
			@media (max-width: 782px) {
				.kc-ml-promo-inner { flex-direction: column; align-items: flex-start; }
				.kc-ml-promo-actions { width: 100%; justify-content: space-between; }
			}
		</style>

		<script>
			(function () {
				var banner   = document.getElementById('kc-ml-promo-banner');
				var dismiss  = document.getElementById('kc-ml-promo-dismiss');
				if (!banner || !dismiss) { return; }
				dismiss.addEventListener('click', function () {
					banner.style.transition = 'opacity .18s ease, transform .18s ease';
					banner.style.opacity    = '0';
					banner.style.transform  = 'translateY(-8px)';
					setTimeout(function () { banner.style.display = 'none'; }, 200);

					var body = new URLSearchParams();
					body.append('action', '<?php echo esc_js( self::AJAX_ACTION ); ?>');
					body.append('nonce',  dismiss.getAttribute('data-nonce') || '');
					fetch(ajaxurl, {
						method:      'POST',
						credentials: 'same-origin',
						headers:     { 'Content-Type': 'application/x-www-form-urlencoded' },
						body:        body.toString()
					}).catch(function () { /* best-effort */ });
				});
			})();
		</script>
		<?php
	}

	// ------------------------------------------------------------------
	// Dismiss handler
	// ------------------------------------------------------------------

	public function handle_dismiss() {
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( array( 'message' => 'not_logged_in' ), 403 );
		}
		check_ajax_referer( self::NONCE_ACTION, 'nonce' );

		$user_id = get_current_user_id();
		if ( $user_id > 0 ) {
			update_user_meta( $user_id, self::USER_META_DISMISSED, time() );
		}
		wp_send_json_success();
	}

	// ------------------------------------------------------------------
	// Helpers
	// ------------------------------------------------------------------

	private static function user_dismissed() {
		if ( ! function_exists( 'get_current_user_id' ) || ! function_exists( 'get_user_meta' ) ) {
			return false;
		}
		$uid = get_current_user_id();
		if ( $uid <= 0 ) {
			return false;
		}
		$value = get_user_meta( $uid, self::USER_META_DISMISSED, true );
		return '' !== (string) $value && '0' !== (string) $value;
	}
}
