<?php

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

class AIEO_SEO_Pillars {

	const LAST_OPT     = 'aieo_seo_pillars_built_at';
	const MIN_INTERVAL = 72000;  
	const TOP_PCT      = 0.10;   

	public static function enabled() {
		return class_exists( 'AIEO_DMM_Settings' ) && AIEO_DMM_Settings::get( 'seo.enabled', false );
	}

	
	public static function default_weights() {
		if ( class_exists( 'AIEO_SEO_Score' ) && 'shop' !== AIEO_SEO_Score::site_profile() ) {
			return array(
				'sales'    => 0.0,
				'turnover' => 0.0,
				'forecast' => 0.0,
				'links'    => 1.0,  
				'behavior' => 0.70, 
			);
		}
		return array(
			'sales'    => 0.45,
			'turnover' => 0.20,
			'forecast' => 0.20,
			'links'    => 0.15,
			'behavior' => 0.15, 
		);
	}

	public static function weights() {
		$w = self::default_weights();
		if ( class_exists( 'AIEO_DMM_Settings' ) ) {
			$saved = AIEO_DMM_Settings::get( 'seo.cornerstone_weights', array() );
			if ( is_array( $saved ) ) {
				foreach ( $w as $k => $v ) {
					if ( isset( $saved[ $k ] ) && is_numeric( $saved[ $k ] ) ) {
						$w[ $k ] = max( 0.0, (float) $saved[ $k ] );
					}
				}
			}
		}
		return $w;
	}

	
	public static function top_pct() {
		$p = self::TOP_PCT;
		if ( class_exists( 'AIEO_DMM_Settings' ) ) {
			$saved = AIEO_DMM_Settings::get( 'seo.pillar_top_pct', null );
			if ( is_numeric( $saved ) && (float) $saved > 0 && (float) $saved <= 1 ) {
				$p = (float) $saved;
			}
		}
		return $p;
	}

	
	public static function overrides() {
		$map = array();
		if ( class_exists( 'AIEO_DMM_Settings' ) ) {
			$saved = AIEO_DMM_Settings::get( 'seo.pillar_overrides', '' );
			
			
			
			if ( is_string( $saved ) && '' !== $saved ) {
				$saved = json_decode( $saved, true );
			}
			if ( is_array( $saved ) ) {
				foreach ( $saved as $pid => $v ) {
					$map[ (int) $pid ] = ( (int) $v === 1 ) ? 1 : 0;
				}
			}
		}
		return $map;
	}

	
	public static function maybe_rebuild() {
		if ( ! self::enabled() ) {
			return;
		}
		if ( class_exists( 'AIEO_SEO_Score' ) && 'content' === AIEO_SEO_Score::site_profile() ) {
			
			
			
			$last = (int) get_option( self::LAST_OPT, 0 );
			if ( ! $last || ( (int) current_time( 'timestamp', true ) - $last ) >= self::MIN_INTERVAL ) {
				self::rebuild();
				update_option( self::LAST_OPT, (int) current_time( 'timestamp', true ), false );
			}
			return;
		}
		$last   = (int) get_option( self::LAST_OPT, 0 );
		$within = $last && ( (int) current_time( 'timestamp', true ) - $last ) < self::MIN_INTERVAL;
		
		
		
		
		if ( $within && self::scores_complete() ) {
			return;
		}
		self::rebuild();
		
		if ( self::scores_complete() ) {
			update_option( self::LAST_OPT, (int) current_time( 'timestamp', true ), false );
		}
	}

	
	private static function scores_complete() {
		global $wpdb;
		$sc = $wpdb->prefix . 'aieo_seo_scores';
		
		$scored    = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$sc}` WHERE object_type = 'product'" );
		$published = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish'" );
		return $published > 0 && $scored >= $published;
	}

	
	public static function rebuild() {
		$out = array( 'updated' => 0, 'pillars' => 0, 'scored' => 0 );
		if ( ! self::enabled() ) {
			return $out;
		}
		global $wpdb;
		$sp = $wpdb->prefix . 'aieo_sales_predictor';
		$sc = $wpdb->prefix . 'aieo_seo_scores';

		
		
		
		$out['content_pillars'] = self::rebuild_content_pillars();

		$profile = class_exists( 'AIEO_SEO_Score' ) ? AIEO_SEO_Score::site_profile() : 'shop';
		if ( 'content' === $profile ) {
			return $out; 
		}

		if ( 'shop' === $profile ) {
			
			$anchor = $wpdb->get_var( "SELECT MAX(prediction_date) FROM `{$sp}` WHERE grain = 'parent'" );
			if ( ! $anchor ) {
				return $out;
			}

			
			
			$rows = $wpdb->get_results( $wpdb->prepare(
				"SELECT product_id, total_product_sales, total_product_turnover, quantity_next_28_days
				 FROM `{$sp}` WHERE grain = 'parent' AND prediction_date = %s",
				$anchor
			), ARRAY_A );
		} else {
			
			
			
			
			
			$rows = array();
			foreach ( (array) $wpdb->get_col(
				"SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish'"
			) as $pid ) {
				$rows[] = array(
					'product_id'            => (int) $pid,
					'total_product_sales'   => 0,
					'total_product_turnover' => 0,
					'quantity_next_28_days' => 0,
				);
			}
		}
		if ( empty( $rows ) ) {
			return $out;
		}

		
		
		
		
		
		$cent   = array();
		$tax_in = "'product_cat','product_brand','product_tag'";
		
		foreach ( (array) $wpdb->get_results(
			"SELECT tr.object_id, COUNT(*) AS c
			 FROM {$wpdb->term_relationships} tr
			 INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
			 WHERE tt.taxonomy IN ({$tax_in})
			 GROUP BY tr.object_id",
			ARRAY_A
		) as $r ) {
			$cent[ (int) $r['object_id'] ] = (int) $r['c'];
		}

		$w = self::weights();

		
		
		
		$commerce = array();
		foreach ( $rows as $r ) {
			$pid   = (int) $r['product_id'];
			$sales = max( 0.0, (float) $r['total_product_sales'] );
			$turn  = max( 0.0, (float) $r['total_product_turnover'] );
			$fc    = max( 0.0, (float) $r['quantity_next_28_days'] );
			$c     = isset( $cent[ $pid ] ) ? (int) $cent[ $pid ] : 0;
			$commerce[ $pid ] = $w['sales'] * log( 1 + $sales )
				+ $w['turnover'] * log( 1 + $turn / 100 )
				+ $w['forecast'] * log( 1 + $fc )
				+ $w['links'] * log( 1 + $c );
		}
		if ( empty( $commerce ) ) {
			return $out;
		}

		
		
		
		
		
		$behavior = array();
		$pm       = $wpdb->prefix . 'aieo_product_session_metrics';
		$has_pm   = ( (string) $wpdb->get_var( $wpdb->prepare(
			"SELECT table_name FROM information_schema.TABLES WHERE table_schema = DATABASE() AND table_name = %s",
			$pm
		) ) === $pm );
		if ( $has_pm && $w['behavior'] > 0 ) {
			$bw = class_exists( 'AIEO_SEO_Opportunity_Scorer' )
				? AIEO_SEO_Opportunity_Scorer::config()
				: array( 'corner_w_entry' => 0.4, 'corner_w_onward' => 0.3, 'corner_w_engagement' => 0.3 );
			
			foreach ( (array) $wpdb->get_results(
				"SELECT product_id, total_views, times_first_page, times_last_page, engagement_score
				 FROM `{$pm}` WHERE total_views > 0",
				ARRAY_A
			) as $r ) {
				$pid   = (int) $r['product_id'];
				$views = max( 1, (int) $r['total_views'] );
				$entry  = min( 1.0, (int) $r['times_first_page'] / $views );
				$onward = max( 0.0, 1.0 - ( (int) $r['times_last_page'] / $views ) );
				$eng    = min( 1.0, max( 0.0, (float) $r['engagement_score'] / 100 ) );
				$behavior[ $pid ] = $bw['corner_w_entry'] * $entry
					+ $bw['corner_w_onward'] * $onward
					+ $bw['corner_w_engagement'] * $eng;
			}
		}

		
		
		$cmax = max( $commerce );
		if ( $cmax <= 0 ) {
			$cmax = 1.0;
		}
		$wb    = min( 1.0, max( 0.0, (float) $w['behavior'] ) );
		$final = array();
		foreach ( $commerce as $pid => $cv ) {
			$cn = $cv / $cmax;                                  
			$bn = isset( $behavior[ $pid ] ) ? $behavior[ $pid ] : 0.0; 
			$final[ $pid ] = ( 1 - $wb ) * $cn + $wb * $bn;
		}

		
		
		
		
		
		
		
		$ranked = array_keys( $final );
		usort( $ranked, static function ( $a, $b ) use ( $final ) {
			if ( $final[ $a ] === $final[ $b ] ) {
				return $a <=> $b;
			}
			return ( $final[ $a ] < $final[ $b ] ) ? 1 : -1;
		} );
		$n          = count( $ranked );
		$cut_index  = (int) max( 1, (int) floor( $n * self::top_pct() ) );
		$pillar_set = array_fill_keys( array_slice( $ranked, 0, min( $cut_index, $n ) ), true );

		$overrides = self::overrides();

		
		$ex = array();
		
		foreach ( (array) $wpdb->get_results( "SELECT id, object_id, pillar_score, is_pillar FROM `{$sc}` WHERE object_type = 'product'", ARRAY_A ) as $r ) {
			$ex[ (int) $r['object_id'] ] = $r;
		}
		$out['scored'] = count( $ex );

		foreach ( $final as $pid => $rv ) {
			if ( ! isset( $ex[ $pid ] ) ) {
				continue; 
			}
			$is_pillar = ( $rv > 0 && isset( $pillar_set[ $pid ] ) ) ? 1 : 0;
			
			if ( isset( $overrides[ $pid ] ) ) {
				$is_pillar = $overrides[ $pid ];
			}
			if ( $is_pillar ) {
				$out['pillars']++; 
			}
			$pscore  = (int) round( min( 100.0, $rv * 100.0 ) );
			$cur     = $ex[ $pid ];
			$cur_ip  = (int) $cur['is_pillar'];
			$cur_ps  = (int) round( (float) $cur['pillar_score'] );
			if ( $cur_ip === $is_pillar && $cur_ps === $pscore ) {
				continue; 
			}
			$wpdb->update(
				$sc,
				array( 'pillar_score' => $pscore, 'is_pillar' => $is_pillar ),
				array( 'id' => (int) $cur['id'] ),
				array( '%f', '%d' ),
				array( '%d' )
			);
			$out['updated']++;
		}

		return $out;
	}

	
	private static function rebuild_content_pillars() {
		global $wpdb;
		$cv = $wpdb->prefix . 'aieo_core_content_vitals';
		$sc = $wpdb->prefix . 'aieo_seo_scores';
		if ( (string) $wpdb->get_var( $wpdb->prepare(
			'SELECT table_name FROM information_schema.TABLES WHERE table_schema = DATABASE() AND table_name = %s',
			$cv
		) ) !== $cv ) {
			return 0;
		}
		
		$rows = $wpdb->get_results( "SELECT post_type, content_id, content_demand FROM `{$cv}`", ARRAY_A );
		if ( empty( $rows ) ) {
			return 0;
		}

		
		usort( $rows, static function ( $a, $b ) {
			$d = (int) $b['content_demand'] <=> (int) $a['content_demand'];
			if ( 0 !== $d ) {
				return $d;
			}
			$t = strcmp( (string) $a['post_type'], (string) $b['post_type'] );
			return 0 !== $t ? $t : ( (int) $a['content_id'] <=> (int) $b['content_id'] );
		} );
		$cut        = (int) max( 1, (int) floor( count( $rows ) * self::top_pct() ) );
		$pillar_set = array();
		$demand_map = array();
		foreach ( $rows as $i => $r ) {
			$key                = $r['post_type'] . ':' . $r['content_id'];
			$demand_map[ $key ] = (int) $r['content_demand'];
			if ( $i < $cut && (int) $r['content_demand'] > 0 ) {
				$pillar_set[ $key ] = true;
			}
		}

		
		
		$existing = (array) $wpdb->get_results( "SELECT id, object_type, object_id, pillar_score, is_pillar FROM `{$sc}` WHERE object_type <> 'product'", ARRAY_A );
		$flagged  = 0;
		foreach ( $existing as $row ) {
			$key = $row['object_type'] . ':' . $row['object_id'];
			if ( ! isset( $demand_map[ $key ] ) ) {
				continue; 
			}
			$is_pillar = isset( $pillar_set[ $key ] ) ? 1 : 0;
			$pscore    = $demand_map[ $key ];
			if ( $is_pillar ) {
				$flagged++;
			}
			if ( (int) $row['is_pillar'] === $is_pillar && (int) round( (float) $row['pillar_score'] ) === $pscore ) {
				continue;
			}
			$wpdb->update(
				$sc,
				array( 'pillar_score' => $pscore, 'is_pillar' => $is_pillar ),
				array( 'id' => (int) $row['id'] ),
				array( '%f', '%d' ),
				array( '%d' )
			);
		}
		return $flagged;
	}
}
