<?php
/**
 * Person schema type
 *
 * Outputs schema.org/Person markup for team members and authors.
 *
 * @package BW_Schema
 * @since 3.0.0-babel
 */

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

class BW_Schema_Schema_Person extends BW_Schema_Schema_Base {

	/**
	 * Schema type
	 *
	 * @var string
	 */
	protected $type = 'Person';

	/**
	 * Person data (post or array)
	 *
	 * @var WP_Post|array
	 */
	private $person;

	/**
	 * Constructor
	 *
	 * @param WP_Post|int|array $person Person post object, ID, or data array
	 */
	public function __construct( $person = null ) {
		if ( is_numeric( $person ) ) {
			$this->person = get_post( $person );
		} elseif ( is_a( $person, 'WP_Post' ) ) {
			$this->person = $person;
		} elseif ( is_array( $person ) ) {
			$this->person = $person;
		} elseif ( is_object( $person ) && isset( $person->ID ) ) {
			// User object
			$this->person = $person;
		} else {
			$this->person = null;
		}

		parent::__construct();
	}

	/**
	 * Build the person schema
	 *
	 * @return void
	 */
	protected function build() {
		if ( ! $this->person ) {
			return;
		}

		if ( is_array( $this->person ) ) {
			$this->build_from_array();
		} elseif ( is_a( $this->person, 'WP_Post' ) ) {
			$this->build_from_post();
		} elseif ( is_a( $this->person, 'WP_User' ) ) {
			$this->build_from_user();
		}
	}

	/**
	 * Build from array data
	 *
	 * @return void
	 */
	private function build_from_array() {
		$person = $this->person;

		// Name (required)
		$this->set( 'name', $person['name'] ?? '' );

		// URL
		if ( ! empty( $person['url'] ) ) {
			$this->set( 'url', $this->sanitize_url( $person['url'] ) );
		}

		// Job title
		if ( ! empty( $person['job_title'] ) ) {
			$this->set( 'jobTitle', $person['job_title'] );
		}

		// Image/photo
		if ( ! empty( $person['image'] ) ) {
			$this->set_image( $person['image'] );
		}

		// Description/bio
		if ( ! empty( $person['biography'] ) ) {
			$this->set( 'description', $person['biography'] );
		}

		// Email
		if ( ! empty( $person['email'] ) ) {
			$this->set( 'email', $person['email'] );
		}

		// Phone
		if ( ! empty( $person['phone'] ) ) {
			$this->set( 'telephone', $person['phone'] );
		}

		// Organization (employer)
		if ( ! empty( $person['organization'] ) ) {
			$this->set( 'worksFor', array(
				'@type' => 'Organization',
				'name'  => $person['organization'],
			));
		}

		// Social profiles
		$this->set_social_profiles( $person );
	}

	/**
	 * Build from post object (team member post)
	 *
	 * @return void
	 */
	private function build_from_post() {
		$post = $this->person;

		// Name from title
		$this->set( 'name', get_the_title( $post->ID ) );

		// URL
		$this->set( 'url', get_permalink( $post->ID ) );

		// Featured image (photo)
		if ( has_post_thumbnail( $post->ID ) ) {
			$image_id = get_post_thumbnail_id( $post->ID );
			$image_url = wp_get_attachment_url( $image_id );
			if ( $image_url ) {
				$this->set_image_url( $image_url );
			}
		}

		// Description from post content/excerpt
		if ( $post->post_excerpt ) {
			$this->set( 'description', wp_strip_all_tags( $post->post_excerpt ) );
		} elseif ( $post->post_content ) {
			$bio = wp_strip_all_tags( $post->post_content );
			$this->set( 'description', html_entity_decode( wp_trim_words( $bio, 50 ), ENT_QUOTES, 'UTF-8' ) );
		}

		// Job title — team posts store it in 'title' meta; fall back to '_job_title'
		$job_title = get_post_meta( $post->ID, 'title', true );
		if ( ! $job_title ) {
			$job_title = get_post_meta( $post->ID, '_job_title', true );
		}
		if ( $job_title ) {
			$this->set( 'jobTitle', $job_title );
		}

		// Link the person to the organization
		if ( class_exists( 'BW_Schema_Service_Organization' ) ) {
			$org = BW_Schema_Service_Organization::get();
			if ( ! empty( $org['name'] ) ) {
				$this->set_nested( 'worksFor', array(
					'@type' => 'Organization',
					'name'  => $org['name'],
					'url'   => ! empty( $org['url'] ) ? $org['url'] : home_url( '/' ),
				) );
			}
		}

		$email = get_post_meta( $post->ID, '_email', true );
		if ( $email ) {
			$this->set( 'email', $email );
		}

		$phone = get_post_meta( $post->ID, '_phone', true );
		if ( $phone ) {
			$this->set( 'telephone', $phone );
		}
	}

	/**
	 * Build from WordPress user object
	 *
	 * @return void
	 */
	private function build_from_user() {
		$user = $this->person;

		// Name from display name
		$this->set( 'name', $user->display_name );

		// URL (author page)
		$author_url = get_author_posts_url( $user->ID );
		if ( $author_url ) {
			$this->set( 'url', $author_url );
		}

		// Email
		if ( $user->user_email ) {
			$this->set( 'email', $user->user_email );
		}

		// Description from user bio
		if ( $user->description ) {
			$this->set( 'description', $user->description );
		}

		// Try to get avatar (Gravatar)
		$avatar_url = get_avatar_url( $user->ID );
		if ( $avatar_url ) {
			$this->set_image_url( $avatar_url );
		}
	}

	/**
	 * Set image from URL
	 *
	 * @param string $url Image URL
	 * @return void
	 */
	private function set_image_url( $url ) {
		$url = $this->sanitize_url( $url );
		if ( ! $url ) {
			return;
		}

		$this->set_nested( 'image', array(
			'@type' => 'ImageObject',
			'url'   => $url,
		));
	}

	/**
	 * Set image from attachment ID
	 *
	 * @param int $image_id Attachment ID or URL string
	 * @return void
	 */
	private function set_image( $image_id ) {
		if ( is_numeric( $image_id ) ) {
			$url = wp_get_attachment_url( $image_id );
		} else {
			$url = $image_id;
		}

		$this->set_image_url( $url );
	}

	/**
	 * Set social media profiles
	 *
	 * @param array $person Person data
	 * @return void
	 */
	private function set_social_profiles( $person ) {
		$profiles = array();

		$social_fields = array(
			'facebook_url',
			'twitter_url',
			'linkedin_url',
			'instagram_url',
			'youtube_url',
			'website_url',
			'blog_url',
		);

		foreach ( $social_fields as $field ) {
			if ( ! empty( $person[ $field ] ) ) {
				$url = $this->sanitize_url( $person[ $field ] );
				if ( $url ) {
					$profiles[] = $url;
				}
			}
		}

		if ( ! empty( $profiles ) ) {
			$this->set( 'sameAs', $profiles );
		}
	}

	/**
	 * Validate person schema
	 *
	 * Person requires at least a name.
	 *
	 * @return array Validation errors
	 */
	public function validate() {
		$errors = parent::validate();

		if ( ! $this->person ) {
			$errors[] = 'Person schema requires a valid person object';
			return $errors;
		}

		// Check required name
		if ( ! $this->has_required( array( 'name' ) ) ) {
			$errors[] = 'Person schema requires a name';
		}

		return $errors;
	}
}
