<?php
/**
 * Data Providers (Persona Dashboards).
 *
 * Generic, dependency-free data for the persona widgets, drawn entirely from
 * core WordPress: content counts, publishing activity, comment/community
 * signals, user growth, and per-author stats. Where WooCommerce is present, an
 * optional adapter adds store figures — but it is never required.
 *
 * Everything here is read-only and bounded. Heavier aggregates are designed to
 * be called behind the DataCache, never directly on page load.
 *
 * @package Platform\Helm\Modules\Persona_Dashboards
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Persona_Dashboards;

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

final class DataProviders {

	/* ===================================================================== *
	 * CONTENT (manager + editor)
	 * ===================================================================== */

	/**
	 * Published post counts by type.
	 *
	 * @return array<string,int>
	 */
	public function content_counts(): array {
		$out = [];
		foreach ( [ 'post', 'page' ] as $type ) {
			$counts = wp_count_posts( $type );
			$out[ $type ] = isset( $counts->publish ) ? (int) $counts->publish : 0;
		}
		return $out;
	}

	public function posts_published_in_last_days( int $days ): int {
		global $wpdb;
		$since = gmdate( 'Y-m-d H:i:s', time() - $days * DAY_IN_SECONDS );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		return (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->posts}
			 WHERE post_type = 'post' AND post_status = 'publish' AND post_date_gmt >= %s",
			$since
		) );
	}

	public function draft_count(): int {
		$counts = wp_count_posts( 'post' );
		return isset( $counts->draft ) ? (int) $counts->draft : 0;
	}

	public function pending_count(): int {
		$counts = wp_count_posts( 'post' );
		return isset( $counts->pending ) ? (int) $counts->pending : 0;
	}

	/**
	 * Daily publish counts for the last N days (oldest first) — sparkline.
	 *
	 * @return int[]
	 */
	public function daily_publishing( int $days ): array {
		global $wpdb;
		$since = gmdate( 'Y-m-d', time() - $days * DAY_IN_SECONDS );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$rows = $wpdb->get_results( $wpdb->prepare(
			"SELECT DATE(post_date_gmt) d, COUNT(*) c
			 FROM {$wpdb->posts}
			 WHERE post_type = 'post' AND post_status = 'publish' AND post_date_gmt >= %s
			 GROUP BY DATE(post_date_gmt)",
			$since . ' 00:00:00'
		), ARRAY_A );
		$by_day = [];
		foreach ( (array) $rows as $r ) {
			$by_day[ (string) $r['d'] ] = (int) $r['c'];
		}
		$series = [];
		for ( $i = $days - 1; $i >= 0; $i-- ) {
			$day = gmdate( 'Y-m-d', time() - $i * DAY_IN_SECONDS );
			$series[] = $by_day[ $day ] ?? 0;
		}
		return $series;
	}

	/**
	 * Most recent published posts.
	 *
	 * @return array<int,array{id:int,title:string,date:int,author:string,edit_link:string}>
	 */
	public function recent_posts( int $limit = 8 ): array {
		$q = new \WP_Query( [
			'post_type'      => 'post',
			'post_status'    => 'publish',
			'posts_per_page' => max( 1, $limit ),
			'orderby'        => 'date',
			'order'          => 'DESC',
			'no_found_rows'  => true,
		] );
		$out = [];
		foreach ( $q->posts as $p ) {
			$out[] = [
				'id'        => (int) $p->ID,
				'title'     => (string) ( $p->post_title ?: __( '(no title)', 'platform-helm' ) ),
				'date'      => (int) get_post_time( 'U', true, $p ),
				'author'    => (string) get_the_author_meta( 'display_name', (int) $p->post_author ),
				'edit_link' => (string) get_edit_post_link( $p->ID ),
			];
		}
		return $out;
	}

	/**
	 * Top published posts by comment count (a universal engagement proxy).
	 *
	 * @return array<int,array{id:int,title:string,comments:int,edit_link:string}>
	 */
	public function top_posts_by_comments( int $limit = 5 ): array {
		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$rows = $wpdb->get_results( $wpdb->prepare(
			"SELECT ID, post_title, comment_count
			 FROM {$wpdb->posts}
			 WHERE post_type = 'post' AND post_status = 'publish' AND comment_count > 0
			 ORDER BY comment_count DESC
			 LIMIT %d",
			max( 1, $limit )
		), ARRAY_A );
		$out = [];
		foreach ( (array) $rows as $r ) {
			$out[] = [
				'id'        => (int) $r['ID'],
				'title'     => (string) ( $r['post_title'] ?: __( '(no title)', 'platform-helm' ) ),
				'comments'  => (int) $r['comment_count'],
				'edit_link' => (string) get_edit_post_link( (int) $r['ID'] ),
			];
		}
		return $out;
	}

	/* ===================================================================== *
	 * AUTHOR (per-user)
	 * ===================================================================== */

	/**
	 * @return array{published:int,drafts:int,pending:int,comments:int}
	 */
	public function author_stats( int $user_id ): array {
		global $wpdb;
		$counts = count_user_posts( $user_id, 'post', true );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$drafts = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_author = %d AND post_type='post' AND post_status='draft'",
			$user_id
		) );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$pending = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_author = %d AND post_type='post' AND post_status='pending'",
			$user_id
		) );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$comments = (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COALESCE(SUM(comment_count),0) FROM {$wpdb->posts} WHERE post_author = %d AND post_type='post' AND post_status='publish'",
			$user_id
		) );
		return [
			'published' => (int) $counts,
			'drafts'    => $drafts,
			'pending'   => $pending,
			'comments'  => $comments,
		];
	}

	/**
	 * @return array<int,array{id:int,title:string,date:int,status:string,edit_link:string}>
	 */
	public function author_recent_posts( int $user_id, int $limit = 5 ): array {
		$q = new \WP_Query( [
			'author'         => $user_id,
			'post_type'      => 'post',
			'post_status'    => [ 'publish', 'draft', 'pending', 'future' ],
			'posts_per_page' => max( 1, $limit ),
			'orderby'        => 'modified',
			'order'          => 'DESC',
			'no_found_rows'  => true,
		] );
		$out = [];
		foreach ( $q->posts as $p ) {
			$out[] = [
				'id'        => (int) $p->ID,
				'title'     => (string) ( $p->post_title ?: __( '(no title)', 'platform-helm' ) ),
				'date'      => (int) get_post_modified_time( 'U', true, $p ),
				'status'    => (string) $p->post_status,
				'edit_link' => (string) get_edit_post_link( $p->ID ),
			];
		}
		return $out;
	}

	/* ===================================================================== *
	 * COMMUNITY (comments as the universal community signal)
	 * ===================================================================== */

	public function comments_in_last_hours( int $hours ): int {
		global $wpdb;
		$since = gmdate( 'Y-m-d H:i:s', time() - $hours * HOUR_IN_SECONDS );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		return (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_approved = '1' AND comment_date_gmt >= %s",
			$since
		) );
	}

	public function pending_comments_count(): int {
		$counts = wp_count_comments();
		return isset( $counts->moderated ) ? (int) $counts->moderated : 0;
	}

	public function spam_comments_count(): int {
		$counts = wp_count_comments();
		return isset( $counts->spam ) ? (int) $counts->spam : 0;
	}

	/**
	 * @return array<int,array{author:string,post_title:string,date:int,excerpt:string,link:string}>
	 */
	public function recent_comments( int $limit = 8 ): array {
		$comments = get_comments( [
			'status' => 'approve',
			'number' => max( 1, $limit ),
			'orderby'=> 'comment_date_gmt',
			'order'  => 'DESC',
		] );
		$out = [];
		foreach ( (array) $comments as $c ) {
			$out[] = [
				'author'     => (string) $c->comment_author,
				'post_title' => (string) get_the_title( (int) $c->comment_post_ID ),
				'date'       => (int) strtotime( (string) $c->comment_date_gmt ),
				'excerpt'    => wp_trim_words( (string) $c->comment_content, 14 ),
				'link'       => (string) get_comment_link( $c ),
			];
		}
		return $out;
	}

	/* ===================================================================== *
	 * USERS (manager)
	 * ===================================================================== */

	public function total_users(): int {
		$c = count_users();
		return (int) ( $c['total_users'] ?? 0 );
	}

	public function users_registered_in_last_days( int $days ): int {
		global $wpdb;
		$since = gmdate( 'Y-m-d H:i:s', time() - $days * DAY_IN_SECONDS );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		return (int) $wpdb->get_var( $wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->users} WHERE user_registered >= %s",
			$since
		) );
	}

	/* ===================================================================== *
	 * WOOCOMMERCE (optional adapter — only if active)
	 * ===================================================================== */

	public function has_woocommerce(): bool {
		return class_exists( 'WooCommerce' );
	}

	/**
	 * @return array{orders_7d:int,revenue_7d:float}|null
	 */
	public function woo_snapshot(): ?array {
		if ( ! $this->has_woocommerce() || ! function_exists( 'wc_get_orders' ) ) {
			return null;
		}
		$since  = gmdate( 'Y-m-d H:i:s', time() - 7 * DAY_IN_SECONDS );
		$orders = wc_get_orders( [
			'limit'        => 200,
			'status'       => [ 'wc-completed', 'wc-processing' ],
			'date_created' => '>=' . $since,
			'return'       => 'objects',
		] );
		$count   = 0;
		$revenue = 0.0;
		foreach ( (array) $orders as $o ) {
			$count++;
			if ( is_object( $o ) && method_exists( $o, 'get_total' ) ) {
				$revenue += (float) $o->get_total();
			}
		}
		return [ 'orders_7d' => $count, 'revenue_7d' => $revenue ];
	}
}
