<?php
/**
 * Promotes distilled companion facts into the structured companion profile.
 *
 * @package Niwa_AI
 */

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

class Niwa_AI_Companion_Profile_Promoter {
	/** @var object|null */
	private $workspace;

	public function __construct( $workspace = null ) {
		$this->workspace = $workspace;
	}

	public function set_workspace( $workspace ) {
		$this->workspace = $workspace;
	}

	public function promote( $facts ) {
		if ( ! $this->workspace || ! method_exists( $this->workspace, 'get_companion_memory_profile' ) || ! method_exists( $this->workspace, 'save_companion_memory_profile' ) ) {
			return false;
		}

		$profile  = (array) $this->workspace->get_companion_memory_profile();
		$original = $profile;

		foreach ( (array) $facts as $entry ) {
			$this->apply_fact( $profile, $entry );
		}
		$this->normalize_profile_lists( $profile );

		$changed = $this->encode( $profile ) !== $this->encode( $original );
		if ( $changed ) {
			$this->workspace->save_companion_memory_profile( $profile, false );
			if ( method_exists( $this->workspace, 'sync_companion_memory_profile_snapshot' ) ) {
				$this->workspace->sync_companion_memory_profile_snapshot( $profile );
			}
		}

		return $changed;
	}

	private function apply_fact( &$profile, $entry ) {
		$entry    = is_array( $entry ) ? $entry : array();
		$category = isset( $entry['category'] ) ? $this->sanitize_key( (string) $entry['category'] ) : 'other';
		$fact     = isset( $entry['fact'] ) ? $this->normalize_inline_text( $entry['fact'] ) : '';
		if ( '' === $fact ) {
			return;
		}

		if ( 'identity_name' === $category ) {
			$name = class_exists( 'Niwa_AI_Identity_Name' ) ? Niwa_AI_Identity_Name::normalize( $fact ) : '';
			if ( '' !== $name ) {
				$profile['assistant_name'] = $name;
			}
			return;
		}

		if ( 'identity_persona' === $category ) {
			$profile['companion_summary'] = $this->merge_text_block(
				isset( $profile['companion_summary'] ) ? $profile['companion_summary'] : '',
				$fact,
				1200
			);
			$profile['assistant_personality_facets'] = $this->merge_unique_text_items(
				isset( $profile['assistant_personality_facets'] ) ? $profile['assistant_personality_facets'] : array(),
				array( $fact ),
				10
			);
			return;
		}

		if ( 'user_name' === $category ) {
			$name = class_exists( 'Niwa_AI_Identity_Name' ) ? Niwa_AI_Identity_Name::normalize( $fact ) : '';
			if ( '' !== $name ) {
				$profile['founder_name'] = $name;
			}
			$profile['founder_preferences'] = $this->merge_unique_text_items(
				isset( $profile['founder_preferences'] ) ? $profile['founder_preferences'] : array(),
				array( $fact ),
				10
			);
			return;
		}

		if ( 'founder_address' === $category ) {
			$profile['founder_address'] = $this->normalize_memory_candidate( $fact );
			return;
		}

		if ( in_array( $category, array( 'user_preference', 'communication_preference', 'shared_context' ), true ) ) {
			$profile['founder_preferences'] = $this->merge_unique_text_items(
				isset( $profile['founder_preferences'] ) ? $profile['founder_preferences'] : array(),
				array( $fact ),
				10
			);
			if ( 'communication_preference' === $category ) {
				$profile['communication_preferences'] = $this->merge_unique_text_items(
					isset( $profile['communication_preferences'] ) ? $profile['communication_preferences'] : array(),
					array( $fact ),
					8
				);
			}
			return;
		}

		if ( 'relationship_tone' === $category ) {
			$profile['relationship_style'] = $this->merge_text_block(
				isset( $profile['relationship_style'] ) ? $profile['relationship_style'] : '',
				$fact,
				1200
			);
			$this->append_relationship_history( $profile, $fact );
			return;
		}

		if ( 'inside_joke' === $category ) {
			$profile['relationship_notes'] = $this->merge_text_block(
				isset( $profile['relationship_notes'] ) ? $profile['relationship_notes'] : '',
				$fact,
				1200
			);
			$this->append_relationship_history( $profile, $fact );
			return;
		}

		$this->append_relationship_history( $profile, $fact );
	}

	private function normalize_profile_lists( &$profile ) {
		foreach ( array(
			'founder_preferences'       => 10,
			'communication_preferences' => 8,
			'motivators'                => 10,
			'boundaries'                => 10,
			'memory_priorities'         => 8,
			'decision_principles'       => 8,
			'diary_focus'               => 8,
			'current_focus_areas'       => 10,
			'assistant_personality_facets' => 10,
		) as $key => $limit ) {
			if ( isset( $profile[ $key ] ) && is_array( $profile[ $key ] ) ) {
				$profile[ $key ] = $this->merge_unique_text_items( $profile[ $key ], array(), $limit );
			}
		}
	}

	private function append_relationship_history( &$profile, $fact ) {
		$profile['relationship_history_summary'] = $this->merge_text_block(
			isset( $profile['relationship_history_summary'] ) ? $profile['relationship_history_summary'] : '',
			$fact,
			1600
		);
	}

	private function merge_unique_text_items( $existing, $candidates, $limit = 10 ) {
		if ( class_exists( 'Niwa_AI_Companion_Memory_Text' ) ) {
			return Niwa_AI_Companion_Memory_Text::merge_unique_items( $existing, $candidates, $limit );
		}

		return array_slice( array_values( array_unique( array_merge( (array) $existing, (array) $candidates ) ) ), -max( 1, intval( $limit ) ) );
	}

	private function merge_text_block( $existing, $addition, $limit = 800 ) {
		$existing = trim( (string) $existing );
		$addition = $this->normalize_memory_candidate( $addition );
		if ( '' === $addition ) {
			return $this->truncate_block( $existing, $limit );
		}
		if ( '' !== $existing && false !== stripos( $existing, $addition ) ) {
			return $this->truncate_block( $existing, $limit );
		}

		$merged = trim( implode( "\n", array_filter( array( $existing, '- ' . $addition ) ) ) );
		return $this->truncate_block( $merged, $limit );
	}

	private function normalize_memory_candidate( $text ) {
		if ( class_exists( 'Niwa_AI_Companion_Memory_Text' ) ) {
			return Niwa_AI_Companion_Memory_Text::normalize_candidate( $text, 220, 1 );
		}

		$text = $this->normalize_inline_text( $text );
		return $this->truncate_block( trim( (string) $text, " \t\n\r\0\x0B:-" ), 220 );
	}

	private function normalize_inline_text( $text ) {
		if ( class_exists( 'Niwa_AI_Companion_Memory_Text' ) ) {
			return Niwa_AI_Companion_Memory_Text::normalize_inline( $text );
		}

		$text = wp_strip_all_tags( (string) $text );
		$text = preg_replace( '/\s+/u', ' ', $text );
		return trim( (string) $text );
	}

	private function truncate_block( $text, $limit ) {
		if ( class_exists( 'Niwa_AI_Companion_Memory_Text' ) ) {
			return Niwa_AI_Companion_Memory_Text::truncate( $text, $limit );
		}

		$text  = (string) $text;
		$limit = max( 1, intval( $limit ) );
		if ( function_exists( 'mb_strlen' ) && function_exists( 'mb_substr' ) ) {
			return mb_strlen( $text, 'UTF-8' ) > $limit ? rtrim( mb_substr( $text, 0, $limit, 'UTF-8' ) ) : $text;
		}

		return strlen( $text ) > $limit ? rtrim( substr( $text, 0, $limit ) ) : $text;
	}

	private function strtolower( $text ) {
		$text = (string) $text;
		return function_exists( 'mb_strtolower' ) ? mb_strtolower( $text, 'UTF-8' ) : strtolower( $text );
	}

	private function sanitize_key( $value ) {
		if ( function_exists( 'sanitize_key' ) ) {
			return sanitize_key( $value );
		}

		return strtolower( preg_replace( '/[^a-z0-9_\-]/i', '', (string) $value ) );
	}

	private function encode( $value ) {
		return function_exists( 'wp_json_encode' ) ? wp_json_encode( $value ) : json_encode( $value );
	}
}
