<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

/**
 * Class BWFCRM_Exporter
 * @package Autonami CRM
 */
#[AllowDynamicProperties]
class BWFCRM_Exporter {
	/** Export type */
	public static $EXPORT = 2;
	/** Export Status */
	public static $EXPORT_IN_PROGRESS = 1;
	public static $EXPORT_FAILED = 2;
	public static $EXPORT_SUCCESS = 3;
	private static $ins = null;
	/**
	 * Export action
	 *
	 * @var string
	 */
	private static $ACTION_HOOK = 'bwfcrm_contact_export';
	private $start_time = 0;
	private $current_pos = 0;

	private $db_export_row = array();
	private $export_meta = array();
	private $export_fields = array();
	private $export_filters = array();
	private $export_id = 0;

	protected $halt = 0;
	protected $count = 0;
	protected $contacts = array();

	public function __construct() {
		add_action( 'wp_loaded', [ $this, 'bwfcrm_exporter_action' ], 9 );
	}

	public static function get_instance() {
		if ( null === self::$ins ) {
			self::$ins = new self();
		}

		return self::$ins;
	}

	/**
	 * Added row in table and start action
	 *
	 * @param $title
	 * @param $fields
	 * @param $filters
	 * @param $count
	 *
	 * @return array
	 */
	public static function bwfcrm_add_export_action( $title, $fields, $filters, $count ) {
		$response   = false;
		$fields     = apply_filters( 'bwfcrm_export_fields_headers', $fields );
		$field_data = self::bwfcrm_seperate_slug_label( $fields );
		if ( ! file_exists( BWFCRM_EXPORT_DIR . '/' ) ) {
			wp_mkdir_p( BWFCRM_EXPORT_DIR );
		}

		$file_name = 'FKA-Contacts-Export-' . current_time( 'mysql' ) . '.csv';
		$file_name = str_replace( [ ' ', ':' ], '-', $file_name );
		$file      = fopen( BWFCRM_EXPORT_DIR . '/' . $file_name, "wb" );
		if ( empty( $file ) ) {
			/** Unable to open file, should return and show a message */
			return array(
				'status' => 404
			);
		}

		fputcsv( $file, $field_data['label'] );
		fclose( $file );

		BWFAN_Model_Import_Export::insert( array(
			'offset'        => 0,
			'type'          => self::$EXPORT,
			'status'        => self::$EXPORT_IN_PROGRESS,
			'count'         => $count,
			'meta'          => wp_json_encode( array(
				'title'   => $title,
				'fields'  => $fields,
				'filters' => $filters,
				'file'    => $file_name,
			) ),
			'created_date'  => current_time( 'mysql', 1 ),
			'last_modified' => current_time( 'mysql', 1 )
		) );

		$export_id = BWFAN_Model_Import_Export::insert_id();

		if ( empty( $export_id ) ) {
			/** Unable to insert row in DB */
			wp_delete_file( BWFCRM_EXPORT_DIR . '/' . $file_name );

			return array(
				'status' => 404
			);
		}

		$response = true;
		bwf_schedule_recurring_action( time(), 30, self::$ACTION_HOOK, array( 'export_id' => absint( $export_id ) ), 'bwfcrm' );
		BWFCRM_Common::ping_woofunnels_worker();

		return array(
			'status' => $response,
			'id'     => $export_id,
		);
	}

	public static function bwfcrm_seperate_slug_label( $data ) {
		$fields_slug = [];
		$field_label = [];
		foreach ( $data as $ds ) {
			foreach ( $ds as $key => $val ) {
				$field_label[] = $val;
				$fields_slug[] = $key;
			}
		}

		return [
			'slug'  => $fields_slug,
			'label' => $field_label
		];
	}

	/**
	 * Gget dynamic string
	 *
	 * @param $count
	 *
	 * @return string
	 */
	public static function get_dynamic_string( $count = 8 ) {
		$chars = apply_filters( 'bwfan_dynamic_string_chars', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' );

		return substr( str_shuffle( $chars ), 0, $count );
	}

	/**
	 * Delete export entry
	 *
	 * @param $export_id
	 *
	 * @return bool
	 */
	public static function delete_export_entry( $export_id ) {
		$response = false;
		$data     = BWFAN_Model_Import_Export::get( $export_id );
		if ( ! empty( $data ) ) {
			$stat = BWFAN_Model_Import_Export::delete( $export_id );
			if ( isset( $data['meta'] ) && isset( $data['meta']['file'] ) && file_exists( BWFCRM_EXPORT_DIR . '/' . $data['meta']['file'] ) ) {
				wp_delete_file( BWFCRM_EXPORT_DIR . '/' . $data['meta']['file'] );
			}
			if ( $stat ) {
				$response = true;
			}
		}

		return $response;
	}

	/**
	 * Add Exporter Action
	 */
	public function bwfcrm_exporter_action() {
		add_action( self::$ACTION_HOOK, array( $this, 'bwfcrm_export' ) );
	}

	/**
	 * Export Action callback
	 */
	public function bwfcrm_export( $export_id ) {
		if ( ! $this->maybe_get_export( $export_id ) ) {
			$this->end_export( self::$EXPORT_FAILED, 'Unable to get Export ID: ' . $export_id );

			return;
		}

		if ( $this->is_recently_exported() ) {
			$this->end_export( self::$EXPORT_FAILED, 'Contacts Recent Export attempt: ' . $this->db_export_row['last_modified'] );

			return;
		}
		$field_data           = self::bwfcrm_seperate_slug_label( $this->export_meta['fields'] );
		$this->export_fields  = $field_data['slug'];
		$this->export_filters = isset( $this->export_meta['filters'] ) ? $this->export_meta['filters'] : [];

		if ( ! is_array( $this->export_fields ) || empty( $this->export_fields ) ) {
			$this->end_export( self::$EXPORT_FAILED, 'Export Fields Empty' );

			return;
		}

		$this->current_pos = absint( $this->db_export_row['offset'] );

		$this->populate_contacts();
		$this->start_time = time();

		while ( ( ( time() - $this->start_time ) < 30 ) && ! BWFCRM_Common::memory_exceeded() && ( 0 === $this->halt ) ) {
			/** Populate contacts when previous contacts are done exporting */
			if ( $this->count >= count( $this->contacts ) ) {
				/**
				 * Fetch next set of contacts to export
				 */
				$this->populate_contacts();
			}
			$this->export_contact();
			$this->update_offset();
		}

		if ( $this->get_percent_completed() >= 100 ) {
			$this->end_export( self::$EXPORT_SUCCESS, '' );
		}

	}

	public function populate_contacts() {
		$contacts = BWFCRM_Contact::get_contacts( '', $this->current_pos, 100, $this->export_meta['filters'], [
			'grab_totals'        => true,
			'customer_data'      => true,
			'grab_custom_fields' => true
		], OBJECT, true );

		$this->contacts = isset( $contacts['contacts'] ) ? $contacts['contacts'] : [];
	}

	/**
	 * Check for export id
	 *
	 * @param $export_id
	 *
	 * @return bool
	 */
	public function maybe_get_export( $export_id ) {
		if ( is_array( $this->db_export_row ) && ! empty( $this->db_export_row ) && absint( $this->db_export_row['id'] ) === absint( $export_id ) ) {
			return true;
		}

		$this->export_id     = absint( $export_id );
		$this->db_export_row = BWFAN_Model_Import_Export::get( $this->export_id );

		if ( empty( $this->db_export_row ) ) {
			bwf_unschedule_actions( self::$ACTION_HOOK, array( 'export_id' => absint( $this->export_id ) ), 'bwfcrm' );

			return true;
		}

		$this->export_meta = ! empty( $this->db_export_row['meta'] ) ? json_decode( $this->db_export_row['meta'], true ) : array();
		if ( isset( $this->export_meta['log'] ) && is_array( $this->export_meta['log'] ) ) {
			$this->skipped = isset( $this->export_meta['log']['skipped'] ) && empty( $this->skipped ) ? absint( $this->export_meta['log']['skipped'] ) : $this->skipped;
			$this->succeed = isset( $this->export_meta['log']['succeed'] ) && empty( $this->succeed ) ? absint( $this->export_meta['log']['succeed'] ) : $this->succeed;
			$this->failed  = isset( $this->export_meta['log']['failed'] ) && empty( $this->failed ) ? absint( $this->export_meta['log']['failed'] ) : $this->failed;
		}

		return is_array( $this->db_export_row ) && ! empty( $this->db_export_row );
	}

	/**
	 * Finish exporting to file
	 *
	 * @param int $status
	 * @param string $status_message
	 */
	public function end_export( $status = 3, $status_message = '' ) {
		if ( empty( $this->export_id ) ) {
			return;
		}

		$db_status = absint( $this->db_export_row['status'] );
		if ( bwf_has_action_scheduled( self::$ACTION_HOOK ) && $db_status === self::$EXPORT_IN_PROGRESS ) {
			bwf_unschedule_actions( self::$ACTION_HOOK, array( 'export_id' => absint( $this->export_id ) ), 'bwfcrm' );
		}

		if ( ! empty( $status_message ) ) {
			BWFAN_Core()->logger->log( $status_message, 'export_contacts_crm' );
		} else if ( 3 === $status ) {
			$status_message = __( 'Contacts exported. Export ID: ' . $this->export_id, 'wp-marketing-automations-pro' );
		}

		$this->db_export_row['status']   = $status;
		$this->export_meta['status_msg'] = $status_message;
		BWFAN_Model_Import_Export::update( array(
			"status" => $status,
			"meta"   => wp_json_encode( $this->export_meta )
		), array(
			'id' => absint( $this->export_id )
		) );
	}

	/**
	 * Check last modified time
	 *
	 * @return bool
	 */
	public function is_recently_exported() {
		$status                = absint( $this->db_export_row['status'] );
		$last_modified_seconds = time() - strtotime( $this->db_export_row['last_modified'] );

		return self::$EXPORT_IN_PROGRESS != $status && $last_modified_seconds <= 5;
	}

	/**
	 * Export contact to CSV function
	 */
	public function export_contact() {
		$this->count = 0;

		/** Check if contacts are empty */
		if ( empty( $this->contacts ) ) {
			$this->end_export( self::$EXPORT_SUCCESS, __( 'Contacts not found', 'wp-marketing-automations-pro' ) );


			$this->halt = 1;

			return;
		}

		$file = fopen( BWFCRM_EXPORT_DIR . '/' . $this->export_meta['file'], "a" );
		foreach ( $this->contacts as $contact ) {
			$csvData = $contact->get_contact_info_by_fields( $this->export_fields );

			$csvData = apply_filters( 'bwfcrm_export_csv_row_before_insert', $csvData, $contact, $this->export_fields );
			if ( ! empty( $file ) ) {
				fputcsv( $file, $csvData );
			}
			$this->count ++;
		}
		if ( ! empty( $file ) ) {
			fclose( $file );
		}
		$this->current_pos = $this->current_pos + $this->count;
	}

	/**
	 * Update DB offset
	 */
	public function update_offset() {
		$this->db_export_row['offset'] = $this->current_pos;
		BWFAN_Model_Import_Export::update( array( "offset" => $this->current_pos ), array( 'id' => absint( $this->export_id ) ) );
		if ( $this->get_percent_completed() >= 100 ) {
			$this->end_export( self::$EXPORT_SUCCESS, '' );
		}
	}

	/**
	 * Return percent completed
	 *
	 * @return int
	 */
	public function get_percent_completed() {
		$start_pos = isset( $this->db_export_row['offset'] ) && ! empty( absint( $this->db_export_row['offset'] ) ) ? absint( $this->db_export_row['offset'] ) : 1;

		return absint( min( round( ( ( $start_pos / $this->db_export_row['count'] ) * 100 ) ), 100 ) );
	}
}

if ( class_exists( 'BWFCRM_Exporter' ) ) {
	BWFCRM_Core::register( 'exporter', 'BWFCRM_Exporter' );
}