<?php
/**
 * Usage Manager.
 *
 * @package TryAura
 */

namespace Dokan\TryAura\Database;

use Dokan\TryAura\Models\Usage;
use Dokan\TryAura\TryAura;

if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * Usage Manager class.
 *
 * @since 1.0.0
 */
class UsageManager {

	/**
	 * Cache group.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	const CACHE_GROUP = 'tryaura_usage';

	/**
	 * Get table name.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public static function get_table_name(): string {
		global $wpdb;
		return $wpdb->prefix . 'tryaura';
	}

	/**
	 * Log usage.
	 *
	 * @since 1.0.0
	 *
	 * @param array $data Usage data.
	 *
	 * @return int|bool
	 */
	public function log_usage( array $data ) {
		$usage = new Usage( $data );
		return $this->insert( $usage );
	}

	/**
	 * Insert usage record.
	 *
	 * @since 1.0.0
	 *
	 * @param Usage $usage Usage model.
	 *
	 * @return int|bool
	 */
	public function insert( Usage $usage ) {
		global $wpdb;

		$insert_data = array(
			'user_id'        => $usage->user_id ?? get_current_user_id(),
			'provider'       => $usage->provider ?? 'google',
			'model'          => $usage->model ?? '',
			'type'           => $usage->type ?? 'image',
			'generated_from' => $usage->generated_from ?? 'admin',
			'prompt'         => $usage->prompt ?? '',
			'input_tokens'   => (int) ( $usage->input_tokens ?? 0 ),
			'output_tokens'  => (int) ( $usage->output_tokens ?? 0 ),
			'total_tokens'   => (int) ( $usage->total_tokens ?? 0 ),
			'video_seconds'  => (float) ( $usage->video_seconds ?? 0 ),
			'output_count'   => (int) ( $usage->output_count ?? 1 ),
			'status'         => $usage->status ?? 'success',
			'error_message'  => $usage->error_message ?? null,
			'object_id'      => (int) ( $usage->object_id ?? 0 ),
			'object_type'    => $usage->object_type ?? null,
			'meta'           => is_array( $usage->meta ) ? wp_json_encode( $usage->meta ) : $usage->meta,
			'created_at'     => $usage->created_at ?? current_time( 'mysql' ),
		);

		$wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
			self::get_table_name(),
			$insert_data,
			array(
				'%d', // user_id
				'%s', // provider
				'%s', // model
				'%s', // type
				'%s', // generated_from
				'%s', // prompt
				'%d', // input_tokens
				'%d', // output_tokens
				'%d', // total_tokens
				'%f', // video_seconds
				'%d', // output_count
				'%s', // status
				'%s', // error_message
				'%d', // object_id
				'%s', // object_type
				'%s', // meta
				'%s', // created_at
			)
		);

		wp_cache_set( 'last_changed', microtime(), self::CACHE_GROUP );

		return $wpdb->insert_id;
	}

	/**
	 * Get statistics.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args Filter arguments.
	 *
	 * @return array
	 */
	public function get_stats( array $args = array() ): array {
		global $wpdb;
		$table = self::get_table_name();

		$start_date = isset( $args['start_date'] ) ? sanitize_text_field( $args['start_date'] ) : null;
		$end_date   = isset( $args['end_date'] ) ? sanitize_text_field( $args['end_date'] ) : null;

		$last_changed = wp_cache_get( 'last_changed', self::CACHE_GROUP );
		if ( ! $last_changed ) {
			$last_changed = microtime();
			wp_cache_set( 'last_changed', $last_changed, self::CACHE_GROUP );
		}

		$cache_key = 'stats_' . md5( wp_json_encode( $args ) ) . ':' . $last_changed;
		$stats     = wp_cache_get( $cache_key, self::CACHE_GROUP );

		if ( false !== $stats ) {
			return $stats;
		}

		$where  = "WHERE status = 'success'";
		$params = array();

		if ( $start_date ) {
			$where   .= ' AND created_at >= %s';
			$params[] = $start_date . ' 00:00:00';
		}

		if ( $end_date ) {
			$where   .= ' AND created_at <= %s';
			$params[] = $end_date . ' 23:59:59';
		}


		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$image_count = $wpdb->get_var( $wpdb->prepare( "SELECT SUM(output_count) FROM %i $where AND type = 'image'", array_merge( array( $table ), $params ) ) );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$total_tokens = $wpdb->get_var( $wpdb->prepare( "SELECT SUM(total_tokens) FROM %i $where", array_merge( array( $table ), $params ) ) );

		$stats = array(
			'image_count'   => (int) $image_count,
			'total_tokens'  => (int) $total_tokens,
		);

		$stats = apply_filters('tryaura_admin_dashboard_stats_data', $stats, $table, $where, $params);

		if ( class_exists( 'WooCommerce' ) ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
			$stats['tryon_count'] = (int) $wpdb->get_var( $wpdb->prepare( "SELECT SUM(output_count) FROM %i $where AND generated_from = 'tryon'", array_merge( array( $table ), $params ) ) );
		}

		wp_cache_set( $cache_key, $stats, self::CACHE_GROUP );

		return $stats;
	}

	/**
	 * Get chart data.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args Filter arguments.
	 *
	 * @return array
	 */
	public function get_chart_data( array $args = array() ): array {
		global $wpdb;
		$table = self::get_table_name();
		$is_woocommerce_active = class_exists( 'WooCommerce' );

		$start_date = isset( $args['start_date'] ) ? sanitize_text_field( $args['start_date'] ) : current_time( 'Y-m-01' );
		$end_date   = isset( $args['end_date'] ) ? sanitize_text_field( $args['end_date'] ) : current_time( 'Y-m-d' );

		$last_changed = wp_cache_get( 'last_changed', self::CACHE_GROUP );
		if ( ! $last_changed ) {
			$last_changed = microtime();
			wp_cache_set( 'last_changed', $last_changed, self::CACHE_GROUP );
		}

		$cache_key = 'chart_data_' . md5( wp_json_encode( $args ) ) . ':' . $last_changed;
		$chart_data = wp_cache_get( $cache_key, self::CACHE_GROUP );

		if ( false !== $chart_data ) {
			return $chart_data;
		}

		$where  = "WHERE status = 'success'";
		$params = [ $table ];

		$where   .= ' AND created_at >= %s';
		$params[] = $start_date . ' 00:00:00';

		$where   .= ' AND created_at <= %s';
		$params[] = $end_date . ' 23:59:59';

		$selector_parts = array(
			'DATE(created_at) as date',
			"SUM(CASE WHEN type = 'image' THEN output_count ELSE 0 END) as images",
		);

		if ( $is_woocommerce_active ) {
			$selector_parts[] = "SUM(CASE WHEN generated_from = 'tryon' THEN output_count ELSE 0 END) as tryOns";
		}

		$selector_parts = apply_filters(
			'tryaura_admin_dashboard_chart_data_query_selectors',
			$selector_parts,
			$table,
			$where,
			$params
		);

		$selectors = implode( ', ', $selector_parts );

		// Group by date
		$query = "SELECT
					$selectors
				FROM %i
				$where
				GROUP BY DATE(created_at)
				ORDER BY date ASC";

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared
		$results = $wpdb->get_results( $wpdb->prepare( $query, ...$params ), ARRAY_A );

		$indexed_results = [];
		foreach ( $results as $row ) {
			$indexed_results[ $row['date'] ] = $row;
		}

		$chart_data = [];

		foreach ( $results as $row ) {
			$date_str = $row['date'];
			$date     = new \DateTime( $date_str );

			$chart_item_data = [
				'name'   => $date->format( 'M j' ),
				'images' => (int) $row['images'],
			];

			if ( $is_woocommerce_active ) {
				$chart_item_data['tryOns'] = (int) $row['tryOns'];
			}

			$chart_data[] = apply_filters( 'tryaura_admin_dashboard_chart_data_item', $chart_item_data, $date_str, $indexed_results );
		}

		wp_cache_set( $cache_key, $chart_data, self::CACHE_GROUP );

		return $chart_data;
	}

	/**
	 * Get recent activities.
	 *
	 * @since 1.0.0
	 *
	 * @param array $args Filter arguments.
	 *
	 * @return array
	 */
	public function get_recent_activities( array $args = array() ): array {
		global $wpdb;
		$table = self::get_table_name();

		$limit = isset( $args['limit'] ) ? (int) $args['limit'] : 5;
		$type  = isset( $args['type'] ) ? sanitize_text_field( $args['type'] ) : null;

		$last_changed = wp_cache_get( 'last_changed', self::CACHE_GROUP );
		if ( ! $last_changed ) {
			$last_changed = microtime();
			wp_cache_set( 'last_changed', $last_changed, self::CACHE_GROUP );
		}

		$cache_key = 'recent_activities_' . md5( wp_json_encode( $args ) ) . ':' . $last_changed;
		$results   = wp_cache_get( $cache_key, self::CACHE_GROUP );

		if ( false !== $results ) {
			return $results;
		}

		$where  = "WHERE status = 'success'";
		$params = array( $table );

		if ( $type ) {
			$is_fetchable = ($type === 'image' || $type === 'tryon');
			$is_fetchable = apply_filters('tryaura_recent_activity_type', $is_fetchable, $type );

			if( $is_fetchable === false ) return [];

			if ( $type === 'tryon' ) {
				if ( ! class_exists( 'WooCommerce' )) {
					return array();
				}
				$where .= " AND generated_from = 'tryon'";
			} else {
				$where   .= ' AND type = %s';
				$params[] = $type;
			}
		} else {
			$type_list = array( 'image', 'tryon' );
			$type_list = apply_filters( 'tryaura_recent_activity_type_list', $type_list );

			// Sanitize each type value and use prepare placeholders.
			$type_list      = array_map( 'sanitize_text_field', $type_list );
			$placeholders   = implode( ', ', array_fill( 0, count( $type_list ), '%s' ) );
			$where         .= " AND type IN ($placeholders)";
			$params         = array_merge( $params, $type_list );
		}

		if ( ! class_exists( 'WooCommerce' )) {
			$where .= " AND generated_from != 'tryon'";
		}

		$params[] = $limit;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM %i $where ORDER BY created_at DESC LIMIT %d", ...$params ), ARRAY_A );

		foreach ( $results as &$result ) {
			$result['object_name'] = '';
			if ( ! empty( $result['object_id'] ) ) {
				$result['object_name'] = get_the_title( $result['object_id'] );
			}
			$result['human_time_diff'] = human_time_diff( strtotime( $result['created_at'] ), current_time( 'timestamp' ) ) . ' ' . __( 'ago', 'tryaura' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
		}

		wp_cache_set( $cache_key, $results, self::CACHE_GROUP );

		return $results;
	}
}
