<?php
/**
 * Class Controller file.
 *
 * @package WebToffee\CookieConsent
 */
namespace WebToffee\CookieConsent\Lite\Admin\Modules\Consentlogs\Includes;
use WebToffee\CookieConsent\Lite\Includes\Base_Controller;
use WebToffee\CookieConsent\Lite\Includes\Filesystem;
use stdClass;
use WP_Error;
if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}
/**
 * Handles Cookies Operation
 *
 * @class       Controller
 * @version     3.0.0
 * @package     WebToffee\CookieConsent
 */
class Controller extends Base_Controller {
	/**
	 * Instance of the current class
	 *
	 * @var object
	 */
	private static $instance;
	/**
	 * Cookie items
	 *
	 * @var array
	 */
	protected $logs;
	/**
	 * Cache group
	 *
	 * @var array
	 */
	protected $cache_group = 'consentlogs';
	/**
	 * Table versioning option name.
	 *
	 * @var string
	 */
	protected $table_option = 'consentlogs';
	/**
	 * Unique item identifier.
	 *
	 * @var string
	 */
	protected $id = 'visitor_id';
	/**
	 * Return the current instance of the class
	 *
	 * @return object
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}
	/**
	 * Return a list of Cookies tables
	 *
	 * @return array Cookies tables.
	 */
	protected function get_tables() {
		global $wpdb;
		return array(
			"{$wpdb->prefix}wcc_visitor_logs",
		);
	}
	/**
	 * Get table schema
	 *
	 * @return string
	 */
	protected function get_schema() {
		global $wpdb;
		$collate = '';
		if ( $wpdb->has_cap( 'collation' ) ) {
			$collate = $wpdb->get_charset_collate();
		}
		$tables = "
			CREATE TABLE {$wpdb->prefix}wcc_visitor_logs (
			visitor_id BIGINT NOT NULL AUTO_INCREMENT,
			status varchar(20) NOT NULL,
			ip varchar(250) NOT NULL,
			consent_id varchar(250) NOT NULL,
			log text NOT NULL,
			date_created int(11) NOT NULL,
			PRIMARY KEY  (visitor_id)
			) $collate;
			";
		return $tables;
	}
	/**
	 * Get cookies from database
	 *
	 * @param array  $args Query params.
	 * @param string $fields Column to be fetched.
	 * @param string $date_from Start date for filtering (Y-m-d format).
	 * @param string $date_to End date for filtering (Y-m-d format).
	 * @return array
	 */
	public function get_item_from_db( $args = array(), $fields = '', $date_from = null, $date_to = null ) {
		global $wpdb;
		$items         = array(
			'data'  => array(),
			'count' => 0,
		);
		$paged         = isset( $args['paged'] ) ? $args['paged'] : 1;
		$post_per_page = isset( $args['per_page'] ) ? $args['per_page'] : -1;
		$offset        = ( $paged - 1 ) * $post_per_page;
		$limits        = '';
		if ( $post_per_page > 0 ) {
			$limits = 'LIMIT ' . $offset . ',' . $post_per_page;
		}

		// Build WHERE clause for date filtering
		$where_clause = '';
		$where_params = array();

		if ( $date_from && $date_to ) {
			$where_clause = 'WHERE date_created >= %d AND date_created <= %d';
			$where_params = array( strtotime( $date_from ), strtotime( $date_to ) );
		} elseif ( $date_from ) {
			$where_clause = 'WHERE date_created >= %d';
			$where_params = array( strtotime( $date_from ) );
		} elseif ( $date_to ) {
			$where_clause = 'WHERE date_created <= %d';
			$where_params = array( strtotime( $date_to ) );
		}

		$sql = "SELECT * FROM {$wpdb->prefix}wcc_visitor_logs $where_clause ORDER BY visitor_id DESC $limits";

		try {
			if ( ! empty( $where_params ) ) {
				$results = $wpdb->get_results( $wpdb->prepare( $sql, $where_params ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.NotPrepared
			} else {
				$results = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.NotPrepared
			}

			if ( isset( $results ) && ! empty( $results ) ) {
				if ( true === is_array( $results ) ) {
					foreach ( $results as $data ) {
						$item = $this->prepare_item( $data );
						if ( $item ) {
							array_push( $items['data'], $item );
						}
					}
				}
			}
		} catch ( \Exception $e ) {
			return new WP_Error( 'wcc_error', $e->getMessage() );
		}
		$items['count'] = $this->get_count( $date_from, $date_to );
		return $items;
	}

	/**
	 * Properly sanitize log data before sending to the controllers.
	 *
	 * @param object $data Log raw data.
	 * @return object
	 */
	public function prepare_item( $data ) {
		if ( false === is_object( $data ) ) {
			return false;
		}
		$log               = new stdClass();
		$log->id           = isset( $data->visitor_id ) ? absint( $data->visitor_id ) : 1;
		$log->ip           = isset( $data->ip ) ? sanitize_text_field( $data->ip ) : self::get_ip_address( true );
		$log->log          = isset( $data->log ) ? $this->sanitize_logs( $data->log ) : array();
		$log->status       = isset( $data->status ) ? $data->status : self::get_log_status( $log->log );
		$log->consent_id   = isset( $data->consent_id ) ? sanitize_text_field( $data->consent_id ) : '';
		$log->date_created = isset( $data->date_created ) ? date_i18n( 'M d, Y g:i:s', $data->date_created ) : '';
		return $log;
	}
	public function sanitize_logs( $data = array() ) {
		$items = is_string( $data ) ? json_decode( sanitize_text_field( $data ), true ) : $data;
		$logs  = array();
		if ( empty( $items ) ) {
			return $logs;
		}
		foreach ( $items as $item ) {
			$log    = array(
				'name'   => isset( $item['name'] ) ? sanitize_text_field( $item['name'] ) : '',
				'status' => isset( $item['status'] ) && 'yes' === $item['status'] ? 'yes' : 'no',
			);
			$logs[] = $log;
		}
		return $logs;
	}
	/**
	 * Calculate the log status based on the log data
	 *
	 * @param array $log Log data.
	 * @return integer
	 */
	private static function get_log_status( $items = array() ) {
		$status   = 'rejected';
		$accepted = array();
		$rejected = array();
		if ( ! $items ) {
			return $status;
		}
		$total = count( $items ) - 1;
		foreach ( $items as $item ) {
			if ( isset( $item['name'] ) && 'necessary' === $item['name'] ) {
				continue;
			}
			$status = isset( $item['status'] ) && 'yes' === $item['status'] ? true : false;
			$name   = isset( $item['name'] ) ? $item['name'] : '';
			if ( '' === $name ) {
				continue;
			}
			if ( true === $status ) {
				array_push( $accepted, $name );
			} else {
				array_push( $rejected, $name );
			}
		}
		if ( count( $accepted ) === $total ) {
			$status = 'accepted'; // Accepted.
		} elseif ( count( $rejected ) === $total ) {
			$status = 'rejected'; // Rejected.
		} else {
			$status = 'partial'; // Partially accepted.
		}
		return sanitize_text_field( $status );
	}
	/**
	 * Insert a new log to the database
	 *
	 * @param object $data Consent log data.
	 * @return object
	 */
	public function create_item( $data ) {
		global $wpdb;
		$log               = $this->prepare_item( $data, true );
		$date_created      = time();
		$log->date_created = $date_created;
		$result            = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'wcc_visitor_logs',
			array(
				'status'       => $log->status,
				'ip'           => $log->ip,
				'consent_id'   => $log->consent_id,
				'log'          => wp_json_encode( $log->log ),
				'date_created' => $log->date_created,
			),
			array(
				'%s',
				'%s',
				'%s',
				'%s',
				'%d',
			)
		);
		if ( is_wp_error( $result ) ) {
			return new WP_Error( 'wcc_log_insert_error', $result->get_error_message() );
		}
		$log->id = absint( $wpdb->insert_id );
		return $log;
	}
	/**
	 * Get consent logs count
	 *
	 * @since 3.0.0
	 * @param string $date_from Start date for filtering (Y-m-d or Y-m-d H:i:s format).
	 * @param string $date_to End date for filtering (Y-m-d or Y-m-d H:i:s format).
	 * @return int
	 */
	public function get_count( $date_from = null, $date_to = null ) {
		global $wpdb;

		// Build WHERE clause for date filtering
		$where_clause = '';
		$where_params = array();

		if ( $date_from && $date_to ) {
			$where_clause = 'WHERE date_created >= %d AND date_created <= %d';
			$where_params = array( strtotime( $date_from ), strtotime( $date_to ) );
		} elseif ( $date_from ) {
			$where_clause = 'WHERE date_created >= %d';
			$where_params = array( strtotime( $date_from ) );
		} elseif ( $date_to ) {
			$where_clause = 'WHERE date_created <= %d';
			$where_params = array( strtotime( $date_to ) );
		}

		$sql = "SELECT COUNT(*) FROM {$wpdb->prefix}wcc_visitor_logs $where_clause";

		if ( ! empty( $where_params ) ) {
			$count = $wpdb->get_var( $wpdb->prepare( $sql, $where_params ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.NotPrepared
		} else {
			$count = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.NotPrepared
		}

		return absint( $count );
	}
	public static function get_ip_address( $mask = false ) {
		$ipaddress = '';
		if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
			$ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CLIENT_IP'] ) );
		} elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
			$ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) );
		} elseif ( isset( $_SERVER['HTTP_X_FORWARDED'] ) ) {
			$ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED'] ) );
		} elseif ( isset( $_SERVER['HTTP_FORWARDED_FOR'] ) ) {
			$ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_FORWARDED_FOR'] ) );
		} elseif ( isset( $_SERVER['HTTP_FORWARDED'] ) ) {
			$ipaddress = sanitize_text_field( wp_unslash( $_SERVER['HTTP_FORWARDED'] ) );
		} elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
			$ipaddress = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
		} else {
			$ipaddress = 'UNKNOWN';
		}
		if ( '::1' === $ipaddress ) {
			$ipaddress = '127.0.0.1';
		}
		if ( $mask ) {
			$ip_arr = explode( '.', $ipaddress );
			if ( count( $ip_arr ) < 2 ) {
				$ip_arr = explode( ':', $ipaddress );
			}
			$last_index            = count( $ip_arr ) - 1;
			$last_key              = $ip_arr[ $last_index ];
			$last_key              = self::encrypt( $last_key );
			$ip_arr[ $last_index ] = $last_key;
			if ( count( $ip_arr ) < 1 ) {
				$ipaddress = implode( ':', $ip_arr );
			} else {
				$ipaddress = implode( '.', $ip_arr );
			}
		}
		return $ipaddress;
	}
	public static function encrypt( $key ) {
		$key    = self::get_key();
		$result = '';
		for ( $i = 0, $k = strlen( $key ); $i < $k; $i++ ) {
			$char    = substr( $key, $i, 1 );
			$keychar = substr( $key, ( $i % strlen( $key ) ) - 1, 1 );
			$char    = chr( ord( $char ) + ord( $keychar ) );
			$result .= $char;
		}
		return base64_encode( $result );
	}
	public static function decrypt( $key ) {
		$key    = self::get_key();
		$result = '';
		$key    = base64_decode( $key );
		for ( $i = 0, $k = strlen( $key ); $i < $k; $i++ ) {
			$char    = substr( $key, $i, 1 );
			$keychar = substr( $key, ( $i % strlen( $key ) ) - 1, 1 );
			$char    = chr( ord( $char ) - ord( $keychar ) );
			$result .= $char;
		}
		return $result;
	}
	public static function get_key() {
		$encryption_key = apply_filters( 'wt_cli_encryption_key', 512814 );
		return $encryption_key;
	}
	/**
	 * Export consent logs to CSV with optional date range filtering
	 *
	 * @param string $date_from Start date for filtering (Y-m-d format).
	 * @param string $date_to End date for filtering (Y-m-d format).
	 * @return array
	 */
	public function export( $date_from = null, $date_to = null ) {
		$uploads_dir = Filesystem::get_instance()->get_uploads_dir( 'webtoffee' );
		$timestamp   = strtotime( wp_date( 'Y-m-d H:i:s' ) );

		// Allow filtering of date range parameters
		$date_range = apply_filters(
			'wcc_export_date_range',
			array(
				'from' => $date_from,
				'to'   => $date_to,
			)
		);

		$date_from = $date_range['from'];
		$date_to   = $date_range['to'];

		// Create filename (same as original format)
		$csv_filename = "consent-logs-$timestamp.csv";
		$csv_path     = $uploads_dir['path'] . $csv_filename;

		if ( ! is_dir( $uploads_dir['path'] ) ) {
			wp_mkdir_p( $uploads_dir['path'] );
		}

		$custom_headers = array( 'ID', 'Consent ID', 'Status', 'Log', 'Date' );

		// Query data from the table with date range filtering
		$results = $this->get_item_from_db( array(), '', $date_from, $date_to );

		// Initialize WP_Filesystem
		global $wp_filesystem;
		if ( empty( $wp_filesystem ) ) {
			require_once ABSPATH . '/wp-admin/includes/file.php';
			WP_Filesystem();
		}
		
		// Build CSV content
		$csv_content = '';
		
		// Add CSV headers
		$csv_content .= implode( ',', array_map( function( $header ) {
			return '"' . str_replace( '"', '""', $header ) . '"';
		}, $custom_headers ) ) . "\n";
		
		// Add CSV data rows
		foreach ( $results['data'] as $row ) {
			// Customize the order of columns based on your needs
			$formatted_date = gmdate( 'j F Y, H:i:s', strtotime( $row->date_created ) );
			$csv_row = array(
				$row->id,
				$row->consent_id,
				$row->status,
				wp_json_encode( $row->log ),
				$formatted_date,
			);
			
			$csv_content .= implode( ',', array_map( function( $value ) {
				return '"' . str_replace( '"', '""', $value ) . '"';
			}, $csv_row ) ) . "\n";
		}
		
		// Write CSV content to file using WP_Filesystem
		$wp_filesystem->put_contents( $csv_path, $csv_content );

		return array(
			'csv_url'   => $uploads_dir['url'] . $csv_filename,
			'file_name' => $csv_filename,
		);
	}
	/**
	 * Delete consent logs
	 *
	 * @since 3.0.0
	 * @return boolean
	 */
	public function delete() {
		global $wpdb;
		$table_name = $wpdb->prefix . 'wcc_visitor_logs';
		// Delete all rows in the table
		$query  = "DELETE FROM $table_name";
		$status = $wpdb->query( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.NotPrepared
		/**
		 *  Action hook fires after consent report deleted.
		 *
		 *  @since  3.0.0
		 */
		do_action( 'wcc_after_delete_consent_logs' );
		return $status;
	}
	public function update_item( $log ) {}
	public function delete_item( $log ) {}
	protected function load_default() {}
}
