<?php

namespace AcademyProFluentCRM\DeepIntegration;

use AcademyProFluentCRM\AdvancedReport;
use FluentCampaign\App\Services\Commerce\Commerce;
use FluentCampaign\App\Services\Commerce\ContactRelationItemsModel;
use FluentCampaign\App\Services\Commerce\ContactRelationModel;
use FluentCrm\App\Models\Subscriber;
use FluentCrm\App\Services\Helper;
use FluentCrm\Framework\Database\Query\Builder;
use FluentCrm\Framework\Support\Arr;

class DeepIntegration {

	protected $integrationkey = 'academylms';

	public function init() {
		add_filter( 'fluentcrm_deep_integration_providers', array( $this, 'add_deep_integration_provider' ), 10, 1 );
		add_filter('fluentcrm_deep_integration_sync_' . $this->integrationkey, array(
			$this,
			'sync_ld_students'
		), 10, 2);
		add_filter('fluentcrm_deep_integration_save_' . $this->integrationkey, array(
			$this,
			'save_settings'
		), 10, 2);

		add_filter('fluent_crm/advanced_report_providers', function ( $providers ) {
			$providers['academylms'] = [
				'title' => __( 'AcademyLMS', 'academy-pro' ),
			];

			return $providers;
		}, 10, 1);

		add_filter('fluentcrm_advanced_reports_provider_academylms', function ( $provider ) {
			return new AdvancedReport();
		});

		/*
		 * Advanced Filters
		 */
		add_filter( 'fluentcrm_advanced_filter_options', array( $this, 'add_advanced_filter_options' ), 10, 1 );
		add_action('fluentcrm_contacts_filter_' . $this->integrationkey, array(
			$this,
			'add_advanced_filters'
		), 10, 2);

		add_filter('fluentcrm_advanced_filter_suggestions', function ( $suggestions ) {
			if ( ! Commerce::isEnabled( $this->integrationkey ) ) {
				$suggestions[] = [
					'title' => __( 'Sync academylms Students to FluentCRM to segment them by their courses data.', 'academy-pro' ),
					'btn_text' => __( 'View Settings', 'academy-pro' ),
					'provider' => 'academylms',
					'btn_url' => admin_url( 'admin.php?page=fluentcrm-admin#/settings/integration_settings?selected_integration=academylms' )
				];
			}

			return $suggestions;
		});

		// Need to sync the course enrollment/remove status
		$hooks = [
			'academy/course/after_enroll',
			'academy/admin/course_complete_after',
			'academy_pro_enrollment/course/after_cancel_enroll'
		];

		foreach ( $hooks as $hook ) {
			add_action($hook, function ( $courseId, $userId ) use ( $hook ) {

				if ( ! Commerce::isEnabled( 'academylms' ) ) {
					return;
				}

				$this->sync_enrollment_canged( $userId, $courseId, $hook );
			}, 10, 2);
		}
	}

	public function sync_enrollment_canged( $userId, $courseId, $hook ) {
		$settings = $this->get_sync_settings();
		$this->sync_settings( $userId, $settings['contact_status'], $settings['tags'], $settings['lists'] );
	}

	public function get_sync_settings() {
		$defaults = [
			'tags' => [],
			'lists' => [],
			'contact_status' => 'subscribed'
		];

		$settings = fluentcrm_get_option( '_academylms_sync_settings', [] );

		$settings = wp_parse_args( $settings, $defaults );

		$settings['is_enabled'] = Commerce::isEnabled( 'academylms' );

		$settings['tags'] = array_map( 'intval', $settings['tags'] );
		$settings['lists'] = array_map( 'intval', $settings['lists'] );

		return $settings;
	}

	public function sync_settings( $userId, $contactStatus = 'subscribed', $tags = [], $lists = [], $sendDoubleOptin = true, $forceSync = false ) {
		$user = get_user_by( 'ID', $userId );
		if ( ! $user ) {
			return false;
		}

		$courses = $this->get_user_courses( $userId );

		if ( ! $courses ) {
			if ( $forceSync ) {
				$subscriber = FluentCrmApi( 'contacts' )->getContactByUserRef( $userId );
				if ( $subscriber ) {
					ContactRelationItemsModel::where( 'subscriber_id', $subscriber->id )
						->provider( $this->integrationkey )
						->delete();
					ContactRelationModel::provider( $this->integrationkey )
						->where( 'subscriber_id', $subscriber->id )
						->delete();
				}
			}

			return false;
		}

		$contactData = Helper::getWPMapUserInfo( $user );

		$subscriber = FluentCrmApi( 'contacts' )->getContact( $contactData['email'] );

		if ( $subscriber ) {
			$subscriber->fill( $contactData )->save();
		} else {
			$contactData['source'] = 'academylms';
			$contactData['status'] = $contactStatus;
			$subscriber = FluentCrmApi( 'contacts' )->createOrUpdate( $contactData );
		}

		if ( ! $subscriber ) {
			return false;
		}

		if ( 'pending' === $contactStatus && 'pending' === $subscriber->status && $sendDoubleOptin ) {
			$subscriber->sendDoubleOptinEmail();
		}

		if ( $tags ) {
			$subscriber->attachTags( $tags );
		}

		if ( $lists ) {
			$subscriber->attachLists( $lists );
		}

		$courseTimeStamps = [];

		foreach ( $courses as $course ) {
			$courseTimeStamps[] = strtotime( $course['created_at'] );
		}

		$relationData = [
			'subscriber_id' => $subscriber->id,
			'provider' => 'academylms',
			'provider_id' => $userId,
			'created_at' => gmdate( 'Y-m-d H:i:s', min( $courseTimeStamps ) ),
			'total_order_count' => count( $courses ),
			'first_order_date' => gmdate( 'Y-m-d H:i:s', min( $courseTimeStamps ) ),
			'last_order_date' => gmdate( 'Y-m-d H:i:s', max( $courseTimeStamps ) )
		];

		$contactRelation = ContactRelationModel::updateOrCreate([
			'subscriber_id' => $subscriber->id,
			'provider' => 'academylms'
		], $relationData);

		if ( ! $contactRelation ) {
			return false;
		}

		$contactRelation->syncItems( $courses, false, true );

		return [
			'relation' => $contactRelation,
			'subscriber' => $subscriber
		];
	}

	public function get_user_courses( $userId ): array {
		$enrolments = fluentCrmDb()->table( 'posts' )
			->where( 'post_type', 'academy_enrolled' )
			->where( 'post_status', 'completed' )
			->where( 'post_author', $userId )
			->get();

		if ( ! $enrolments ) {
			return [];
		}

		$completedCourses = $this->get_completed_courses( $userId );

		$formattedEnrollments = [];
		foreach ( $enrolments as $enrolment ) {
			$formattedEnrollments[] = [
				'origin_id' => $userId,
				'item_id' => $enrolment->post_parent,
				'item_type' => 'course',
				'provider' => 'academylms',
				'status' => ( $completedCourses && in_array( $enrolment->post_parent, $completedCourses, true ) ) ? 'completed' : 'enrolled',
				'created_at' => $enrolment->post_date,
				'updated_at' => $enrolment->post_modified
			];
		}

		return $formattedEnrollments;
	}

	private function get_completed_courses( $userId ) {
		$completedCourses = fluentCrmDb()->table( 'comments' )
			->where( 'comment_type', 'course_completed' )
			->where( 'comment_author', $userId )
			->where( 'comment_agent', 'academy' )
			->select( [ 'comment_post_ID' ] )
			->get();

		if ( ! $completedCourses ) {
			return [];
		}

		// convert to plain array
		return array_map(function ( $course ) {
			return $course->comment_post_ID;
		}, $completedCourses);
	}

	public function add_deep_integration_provider( $providers ) {
		$providers['academylms'] = [
			'title' => __( 'AcademyLMS', 'academy-pro' ),
			'sub_title' => __( 'With AcademyLMS deep integration with FluentCRM, you easily segment your students by their enrollment, course dates and target your students more efficiently.', 'academy-pro' ),
			'sync_title' => __( 'AcademyLMS students are not synced with FluentCRM yet.', 'academy-pro' ),
			'sync_desc' => __( 'To sync and enable deep integration with AcademyLMS students with FluentCRM, please configure and enable sync.', 'academy-pro' ),
			'sync_button' => __( 'Sync AcademyLMS Students', 'academy-pro' ),
			'settings' => $this->get_sync_settings()
		];

		return $providers;
	}

	public function save_settings( $returnData, $config ) {
		$tags = Arr::get( $config, 'tags', [] );
		$lists = Arr::get( $config, 'lists', [] );
		$contactStatus = Arr::get( $config, 'contact_status', 'subscribed' );

		$settings = [
			'tags' => $tags,
			'lists' => $lists,
			'contact_status' => $contactStatus
		];

		if ( Arr::get( $config, 'action' ) === 'disable' ) {
			Commerce::disableModule( $this->integrationkey );
			$settings['disabled_at'] = current_time( 'mysql' );
		}

		fluentcrm_update_option( '_academylms_sync_settings', $settings );

		return [
			'message' => __( 'Settings have been saved', 'academy-pro' ),
			'settings' => $this->get_sync_settings()
		];
	}

	public function sync_ld_students( $returnData, $config ): array {
		$tags = Arr::get( $config, 'tags', [] );
		$lists = Arr::get( $config, 'lists', [] );
		$contactStatus = Arr::get( $config, 'contact_status', 'subscribed' );

		$settings = [
			'tags' => $tags,
			'lists' => $lists,
			'contact_status' => $contactStatus
		];

		fluentcrm_update_option( '_academylms_sync_settings', $settings );

		$status = $this->sync_students([
			'tags' => $tags,
			'lists' => $lists,
			'new_status' => $contactStatus,
			'double_optin_email' => ( 'pending' === $contactStatus ) ? 'yes' : 'no',
			'import_silently' => 'yes'
		], $config['syncing_page']);

		return [
			'syncing_status' => $status
		];
	}

	public function sync_students( $config, $page ): array {
		$inputs = Arr::only($config, [
			'lists',
			'tags',
			'new_status',
			'double_optin_email',
			'import_silently'
		]);

		$inputs = wp_parse_args($inputs, [
			'lists' => [],
			'tags' => [],
			'new_status' => 'subscribed',
			'double_optin_email' => 'no',
			'import_silently' => 'yes'
		]);

		if ( Arr::get( $inputs, 'import_silently' ) === 'yes' ) {
			if ( ! defined( 'FLUENTCRM_DISABLE_TAG_LIST_EVENTS' ) ) {
				define( 'FLUENTCRM_DISABLE_TAG_LIST_EVENTS', true );
			}
		}

		$sendDoubleOptin = Arr::get( $inputs, 'double_optin_email' ) === 'yes';
		$contactStatus = Arr::get( $inputs, 'new_status', 'subscribed' );

		$startTime = time();

		$lastStudentId = false;
		$runTime = 30;
		if ( 1 === $page ) {
			if ( ! Commerce::isMigrated( true ) ) {
				Commerce::migrate();
			} else {
				Commerce::resetModuleData( $this->integrationkey );
			}
			fluentcrm_update_option( '_academylms_student_sync_count', 0 );
			$runTime = 5;
		}

		$run = true;

		while ( $run ) {
			$offset = (int) fluentcrm_get_option( '_academylms_student_sync_count', 0 );

			$students = fluentCrmDb()->table( 'posts' )
				->where( 'post_type', 'academy_enrolled' )
				->where( 'post_status', 'completed' )
				->orderBy( 'post_author', 'ASC' )
				->groupBy( 'post_author' )
				->select([
					fluentCrmDb()->raw( 'DISTINCT(post_author) as student_user_id' ),
				])
				->offset( $offset )
				->limit( 10 )
				->get();
			if ( $students ) {
				foreach ( $students as $student ) {
					$this->sync_settings($student->student_user_id, $contactStatus, $inputs['tags'],
					$inputs['lists'], $sendDoubleOptin);
					$lastStudentId = $student->student_user_id;

					fluentcrm_update_option( '_academylms_student_sync_count', $offset + 1 );
					$offset++;

					if ( ( time() - $startTime > $runTime ) || fluentCrmIsMemoryExceeded() ) {
						return $this->get_sync_student_status( $lastStudentId );
					}
				}
			} else {
				$run = false;
			}
		}//end while

		return $this->get_sync_student_status( $lastStudentId );
	}

	public function get_sync_student_status( $lastStudentId = false ): array {
		$total = fluentCrmDb()->table( 'posts' )
			->where( 'post_type', 'academy_enrolled' )
			->where( 'post_status', 'completed' )
			->count( fluentCrmDb()->raw( 'DISTINCT post_author' ) );

		$completedCount = fluentcrm_get_option( '_academylms_student_sync_count', 0 );

		$hasMore = $total > $completedCount;

		if ( ! $hasMore ) {
			Commerce::enableModule( 'academylms' );
		}

		return [
			'page_total' => $total,
			'record_total' => $total,
			'has_more' => $hasMore,
			'current_page' => $completedCount,
			'next_page' => $completedCount + 1,
			'reload_page' => ! $hasMore,
			'last_sync_id' => $lastStudentId
		];
	}

	/**
	 * @param \FluentCrm\Framework\Database\Orm\Builder|Builder $query
	 * @param array                                             $filters
	 *
	 * @return \FluentCrm\Framework\Database\Orm\Builder|Builder
	 */
	public function add_advanced_filters( $query, $filters ) {
		return Subscriber::providerQueryBuilder( $query, $filters, $this->integrationkey );
	}

	public function add_advanced_filter_options( $groups ) {
		$disabled = ! Commerce::isEnabled( $this->integrationkey );

		$groups[ $this->integrationkey ] = [
			'label' => 'Academy LMS',
			'value' => $this->integrationkey,
			'children' => [
				[
					'value' => 'last_order_date',
					'label' => __( 'Last Enrollment Date', 'academy-pro' ),
					'type' => 'dates',
					'disabled' => $disabled
				],
				[
					'value' => 'first_order_date',
					'label' => __( 'First Enrollment Date', 'academy-pro' ),
					'type' => 'dates',
					'disabled' => $disabled
				],
				[
					'value' => 'purchased_items',
					'label' => __( 'Enrollment Courses', 'academy-pro' ),
					'type' => 'selections',
					'cacheable' => true,
					'component' => 'product_selector',
					'is_multiple' => true,
					'disabled' => $disabled
				],
				[
					'value' => 'purchased_categories',
					'label' => __( 'Enrollment Categories', 'academy-pro' ),
					'type' => 'selections',
					'component' => 'tax_selector',
					'taxonomy' => 'course-category',
					'is_multiple' => true,
					'disabled' => $disabled
				],
				[
					'value' => 'purchased_tags',
					'label' => __( 'Enrollment Tags', 'academy-pro' ),
					'type' => 'selections',
					'component' => 'tax_selector',
					'taxonomy' => 'course-tag',
					'is_multiple' => true,
					'disabled' => $disabled
				],
				[
					'value' => 'commerce_exist',
					'label' => 'Is a student?',
					'type' => 'selections',
					'is_multiple' => false,
					'disable_values' => true,
					'value_description' => 'This filter will check if a contact has at least one enrolled course or not',
					'custom_operators' => [
						'exist' => 'Yes',
						'not_exist' => 'No',
					],
					'disabled' => $disabled
				]
			],
		];

		return $groups;
	}
}
