<?php namespace MeowCrew\CancellationOffers\Offer\Entity\DiscountOffer;

use MeowCrew\CancellationOffers\Offer\OfferDataProvider;
use MeowCrew\CancellationOffers\Utils\Sanitizer;
use WC_Coupon;

class DiscountOffer {
	
	protected $isEnabled = true;
	protected $offerType = 'coupon';
	protected $title = null;
	protected $description = '';
	protected $surveyOptions = array();
	protected $applyDiscountButtonLabel = '';
	protected $cancelSubscriptionButtonLabel = '';
	protected $couponId = null;
	protected $minimumRenewalsCount = null;
	protected $minimumSubscriptionDaysActive = null;
	protected $allowOfferMultipleTimes = false;
	protected $allowTrials = true;
	
	public function isEnabled(): bool {
		return $this->isEnabled;
	}
	
	public function setIsEnabled( bool $isEnabled ): void {
		$this->isEnabled = $isEnabled;
	}
	
	public function getOfferType(): string {
		return $this->offerType;
	}
	
	public function isAllowTrials(): bool {
		return $this->allowTrials;
	}
	
	public function setAllowTrials( bool $allowTrials ): void {
		$this->allowTrials = $allowTrials;
	}
	
	public function setOfferType( string $offerType ): void {
		
		$offerType = in_array( $offerType, array( 'coupon', 'skip_renewal' ) ) ? $offerType : 'coupon';
		
		$this->offerType = $offerType;
	}
	
	public function isApplicableForSubscription( \WC_Subscription $subscription ): bool {
		if ( ! $this->isEnabled() ) {
			return false;
		}
		
		if ( ! $this->isAllowTrials() && $subscription->get_time( 'trial_end' ) ) {
			return false;
		}
		
		if ( $this->getMinimumRenewalsCount() && $subscription->get_payment_count() < $this->getMinimumRenewalsCount() ) {
			return false;
		}
		
		if ( $this->getMinimumSubscriptionDaysActive() && $subscription->get_date_created()->getTimestamp() >= strtotime( '-' . $this->getMinimumSubscriptionDaysActive() . ' days' ) ) {
			return false;
		}
		
		if ( 'coupon' === $this->getOfferType() ) {
			
			$coupon = $this->getCoupon();
			
			if ( ! $coupon ) {
				return false;
			}
			
			// Coupon already applied
			foreach ( $subscription->get_coupons() as $coupon ) {
				if ( $coupon->get_code() == $this->getCoupon()->get_code() ) {
					return false;
				}
			}
		}
		
		if ( ! $this->isAllowOfferMultipleTimes() && $subscription->meta_exists( '_cos_offer_discount_applied' ) ) {
			return false;
		}
		
		return true;
	}
	
	public function getTitle(): ?string {
		return $this->title;
	}
	
	public function getCoupon(): ?WC_Coupon {
		
		$coupon = new WC_Coupon( $this->getCouponId() );
		
		return $coupon->get_id() ? $coupon : null;
	}
	
	public function setTitle( ?string $title ): void {
		$this->title = $title;
	}
	
	public function getDescription(): ?string {
		return $this->description;
	}
	
	public function setDescription( string $description ): void {
		$this->description = $description;
	}
	
	public function getSurveyOptions(): array {
		return $this->surveyOptions;
	}
	
	public function setSurveyOptions( array $surveyOptions ): void {
		$this->surveyOptions = $surveyOptions;
	}
	
	public function getApplyDiscountButtonLabel(): ?string {
		return $this->applyDiscountButtonLabel;
	}
	
	public function setApplyDiscountButtonLabel( string $applyDiscountButtonLabel ): void {
		$this->applyDiscountButtonLabel = $applyDiscountButtonLabel;
	}
	
	public function getCancelSubscriptionButtonLabel(): ?string {
		return $this->cancelSubscriptionButtonLabel;
	}
	
	public function setCancelSubscriptionButtonLabel( string $cancelSubscriptionButtonLabel ): void {
		$this->cancelSubscriptionButtonLabel = $cancelSubscriptionButtonLabel;
	}
	
	public function getCouponId(): ?int {
		return $this->couponId;
	}
	
	public function setCouponId( ?int $couponId ): void {
		$this->couponId = $couponId;
	}
	
	public function getMinimumRenewalsCount(): ?int {
		return $this->minimumRenewalsCount;
	}
	
	public function setMinimumRenewalsCount( ?int $minimumRenewalsCount ): void {
		$this->minimumRenewalsCount = $minimumRenewalsCount;
	}
	
	public function getMinimumSubscriptionDaysActive(): ?int {
		return $this->minimumSubscriptionDaysActive;
	}
	
	public function setMinimumSubscriptionDaysActive( ?int $minimumSubscriptionDaysActive ): void {
		$this->minimumSubscriptionDaysActive = $minimumSubscriptionDaysActive;
	}
	
	public function isAllowOfferMultipleTimes(): bool {
		return $this->allowOfferMultipleTimes;
	}
	
	public function setAllowOfferMultipleTimes( bool $allowOfferMultipleTimes ): void {
		$this->allowOfferMultipleTimes = $allowOfferMultipleTimes;
	}
	
	public static function getDataSchema(): array {
		return array(
			'is_enabled'                       => array(
				'default'  => 'yes',
				'sanitize' => 'wc_string_to_bool',
			),
			'offer_type'                       => array(
				'default'  => 'coupon',
				'sanitize' => 'sanitize_text_field',
			),
			'title'                            => array(
				'default'  => __( 'Your special offer', 'cancellation-surveys-offers-woocommerce-subscriptions' ),
				'sanitize' => 'sanitize_text_field',
			),
			'description'                      => array(
				'default'  => __( 'As a valued subscriber, you have the opportunity to receive an exclusive 10% discount on your subscription. Accept this offer now; the discount will automatically apply to your next billing cycle.',
					'cancellation-surveys-offers-woocommerce-subscriptions' ),
				'sanitize' => 'wp_kses_post',
			),
			'survey_options'                   => array(
				'default'  => array(),
				'sanitize' => array( Sanitizer::class, 'sanitizeStringArray' ),
			),
			'coupon_id'                        => array(
				'default'  => null,
				'sanitize' => 'intval',
			),
			'apply_discount_button_label'      => array(
				'default'  => __( 'Accept offer', 'cancellation-surveys-offers-woocommerce-subscriptions' ),
				'sanitize' => 'sanitize_text_field',
			),
			'cancel_subscription_button_label' => array(
				'default'  => __( 'Cancel subscription', 'cancellation-surveys-offers-woocommerce-subscriptions' ),
				'sanitize' => 'sanitize_text_field',
			),
			'minimum_renewals_count'           => array(
				'default'  => null,
				'sanitize' => function ( $value ) {
					if ( ! $value || '' == $value ) {
						return null;
					}
					
					return intval( $value );
				},
			),
			'minimum_subscription_days_active' => array(
				'default'  => null,
				'sanitize' => function ( $value ) {
					if ( ! $value || '' == $value ) {
						return null;
					}
					
					return intval( $value );
				},
			),
			'allow_offer_multiple_times'       => array(
				'default'  => 'no',
				'sanitize' => 'wc_string_to_bool',
			),
			'allow_trials'                     => array(
				'default'  => 'yes',
				'sanitize' => 'wc_string_to_bool',
			),
		);
	}
	
	public static function build( $offerId ): self {
		$offerDataProvider = new OfferDataProvider( $offerId, 'discounts' );
		
		$data = array();
		
		foreach ( self::getDataSchema() as $key => $schemaItem ) {
			$value = $offerDataProvider->getMeta( $key, $schemaItem['default'] );
			
			if ( ! is_null( $value ) && is_callable( $schemaItem['sanitize'] ) ) {
				$value = call_user_func( $schemaItem['sanitize'], $value );
			}
			
			$data[ $key ] = $value;
		}
		
		return self::buildFromArray( $data );
	}
	
	public static function buildFromPOST( $postData ): self {
		$data = array();
		
		foreach ( self::getDataSchema() as $key => $schemaItem ) {
			// Check for direct key (array structure) or prefixed key (legacy/flat structure)
			$value = $postData[ $key ] ?? ( $postData[ 'discount_offer_' . $key ] ?? false );
			
			if ( is_callable( $schemaItem['sanitize'] ) ) {
				$value = call_user_func( $schemaItem['sanitize'], $value );
			}
			
			$data[ $key ] = $value;
		}
		
		return self::buildFromArray( $data );
	}
	
	public static function buildDefault(): self {
		$data = array();
		
		foreach ( self::getDataSchema() as $key => $schemaItem ) {
			$value = $schemaItem['default'];
			
			if ( is_callable( $schemaItem['sanitize'] ) ) {
				$value = call_user_func( $schemaItem['sanitize'], $value );
			}
			
			$data[ $key ] = $value;
		}
		
		return self::buildFromArray( $data );
	}
	
	public static function buildFromArrayPublic( array $data ): self {
		return self::buildFromArray( $data );
	}
	
	public function save( $offerId ): void {
		
		$offerDataProvider = new OfferDataProvider( $offerId, 'discounts' );
		
		$offerDataProvider->setMeta( 'is_enabled', wc_bool_to_string( $this->isEnabled() ) );
		$offerDataProvider->setMeta( 'offer_type', $this->getOfferType() );
		
		$offerDataProvider->setMeta( 'coupon_id', $this->getCouponId() );
		$offerDataProvider->setMeta( 'survey_options', $this->getSurveyOptions() );
		
		$offerDataProvider->setMeta( 'title', $this->getTitle() );
		$offerDataProvider->setMeta( 'description', $this->getDescription() );
		
		$offerDataProvider->setMeta( 'apply_discount_button_label', $this->getApplyDiscountButtonLabel() );
		$offerDataProvider->setMeta( 'cancel_subscription_button_label', $this->getCancelSubscriptionButtonLabel() );
		
		$offerDataProvider->setMeta( 'minimum_subscription_days_active', $this->getMinimumSubscriptionDaysActive() );
		$offerDataProvider->setMeta( 'minimum_renewals_count', $this->getMinimumRenewalsCount() );
		
		$offerDataProvider->setMeta( 'allow_offer_multiple_times',
			wc_bool_to_string( $this->isAllowOfferMultipleTimes() ) );
		
		$offerDataProvider->setMeta( 'allow_trials', wc_bool_to_string( $this->isAllowTrials() ) );
	}
	
	protected static function buildFromArray( array $data ): self {
		
		$discountOffer = new self();
		
		$discountOffer->setIsEnabled( wc_string_to_bool( $data['is_enabled'] ?? 'yes' ) );
		$discountOffer->setOfferType( $data['offer_type'] ?? 'coupon' );
		$discountOffer->setCouponId( $data['coupon_id'] ?? null );
		$discountOffer->setSurveyOptions( $data['survey_options'] ?? array() );
		$discountOffer->setTitle( $data['title'] ?? '' );
		$discountOffer->setDescription( $data['description'] ?? '' );
		$discountOffer->setApplyDiscountButtonLabel( $data['apply_discount_button_label'] ?? '' );
		$discountOffer->setCancelSubscriptionButtonLabel( $data['cancel_subscription_button_label'] ?? '' );
		$discountOffer->setMinimumSubscriptionDaysActive( $data['minimum_subscription_days_active'] );
		$discountOffer->setMinimumRenewalsCount( $data['minimum_renewals_count'] );
		$discountOffer->setAllowOfferMultipleTimes( wc_string_to_bool( $data['allow_offer_multiple_times'] ?? 'no' ) );
		$discountOffer->setAllowTrials( wc_string_to_bool( $data['allow_trials'] ?? 'yes' ) );
		
		return $discountOffer;
	}
}
