<?php
/**
 * LocalBusiness schema type
 *
 * Outputs schema.org/LocalBusiness markup for specific business locations.
 *
 * @package BW_Schema
 * @since 3.0.0-babel
 */

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

class BW_Schema_Schema_LocalBusiness extends BW_Schema_Schema_Base {

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

	/**
	 * Location data
	 *
	 * @var array|WP_Post
	 */
	private $location;

	/**
	 * Constructor
	 *
	 * @param int|WP_Post|array $location Location ID, post object, or location data array
	 */
	public function __construct( $location = null ) {
		if ( is_null( $location ) ) {
			// Try to get from current post
			global $post;
			if ( $post ) {
				$this->location = $post;
			}
		} elseif ( is_numeric( $location ) ) {
			$this->location = get_post( $location );
		} elseif ( is_array( $location ) ) {
			$this->location = $location;
		} else {
			$this->location = $location;
		}

		parent::__construct();
	}

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

		// Get location data
		if ( is_array( $this->location ) ) {
			$this->build_from_array();
		} elseif ( is_a( $this->location, 'WP_Post' ) ) {
			$this->build_from_post();
		}

		// Set image from organization logo if not already set
		if ( ! isset( $this->schema['image'] ) && class_exists( 'BW_Schema_Service_Organization' ) ) {
			$org = BW_Schema_Service_Organization::get();
			if ( ! empty( $org['logo_id'] ) ) {
				$logo_url = wp_get_attachment_url( $org['logo_id'] );
				if ( $logo_url ) {
					$this->set_nested( 'image', array(
						'@type' => 'ImageObject',
						'url'   => esc_url_raw( $logo_url ),
					));
				}
			}
		}
	}

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

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

		// Address
		if ( ! empty( $loc['street'] ) || ! empty( $loc['city'] ) ) {
			$this->set_address( $loc );
		}

		// Contact info
		if ( ! empty( $loc['telephone'] ) ) {
			$this->set( 'telephone', $loc['telephone'] );
		}

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

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

		// Service areas
		if ( ! empty( $loc['service_areas'] ) ) {
			$this->set_service_areas( $loc['service_areas'] );
		}

		// Business hours
		if ( ! empty( $loc['business_hours'] ) ) {
			$this->set_business_hours( $loc['business_hours'] );
		}

		// Opening hours specification
		if ( ! empty( $loc['opening_hours'] ) ) {
			$this->set_opening_hours( $loc['opening_hours'] );
		}
	}

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

		// Get location data from post meta
		$loc_data = BW_Schema_Service_Locations::get_location( get_post_meta( $post->ID, '_location_id', true ) );

		if ( $loc_data ) {
			$this->location = $loc_data;
			$this->build_from_array();
		} else {
			// Fallback to post title and content
			$this->set( 'name', get_the_title( $post->ID ) );
			$this->set( 'description', $post->post_excerpt ?: wp_trim_words( $post->post_content, 50 ) );
			$this->set( 'url', get_permalink( $post->ID ) );
		}
	}

	/**
	 * Set address information
	 *
	 * @param array $loc Location data
	 * @return void
	 */
	private function set_address( $loc ) {
		$address = array(
			'@type' => 'PostalAddress',
		);

		if ( ! empty( $loc['street'] ) ) {
			$address['streetAddress'] = $loc['street'];
		}

		if ( ! empty( $loc['city'] ) ) {
			$address['addressLocality'] = $loc['city'];
		}

		if ( ! empty( $loc['state'] ) ) {
			$address['addressRegion'] = $loc['state'];
		}

		if ( ! empty( $loc['postal_code'] ) ) {
			$address['postalCode'] = $loc['postal_code'];
		}

		if ( ! empty( $loc['country'] ) ) {
			$address['addressCountry'] = $loc['country'];
		}

		if ( count( $address ) > 1 ) {
			$this->set_nested( 'address', $address );
		}
	}

	/**
	 * Set service areas
	 *
	 * Service areas are places where the business serves customers.
	 *
	 * @param array $areas Service area names
	 * @return void
	 */
	private function set_service_areas( $areas ) {
		if ( ! is_array( $areas ) || empty( $areas ) ) {
			return;
		}

		// Convert to array of area strings
		$area_names = array();
		foreach ( $areas as $area ) {
			if ( is_array( $area ) && ! empty( $area['name'] ) ) {
				$area_names[] = $area['name'];
			} elseif ( is_string( $area ) ) {
				$area_names[] = $area;
			}
		}

		if ( ! empty( $area_names ) ) {
			$this->set( 'areaServed', $area_names );
		}
	}

	/**
	 * Set business hours (old format)
	 *
	 * @param array $hours Business hours
	 * @return void
	 */
	private function set_business_hours( $hours ) {
		if ( empty( $hours ) || ! is_array( $hours ) ) {
			return;
		}

		$day_map = array(
			'monday'    => 'Monday',
			'tuesday'   => 'Tuesday',
			'wednesday' => 'Wednesday',
			'thursday'  => 'Thursday',
			'friday'    => 'Friday',
			'saturday'  => 'Saturday',
			'sunday'    => 'Sunday',
		);

		$opening_hours = array();

		foreach ( $hours as $day => $time ) {
			if ( empty( $time ) || 'closed' === strtolower( $time ) ) {
				continue;
			}

			$day_label = $day_map[ strtolower( $day ) ] ?? '';
			if ( ! $day_label ) {
				continue;
			}

			if ( strpos( $time, '-' ) ) {
				list( $open, $close ) = explode( '-', $time );

				$opening_hours[] = array(
					'@type'         => 'OpeningHoursSpecification',
					'dayOfWeek'     => $day_label,
					'opens'         => trim( $open ),
					'closes'        => trim( $close ),
				);
			}
		}

		if ( ! empty( $opening_hours ) ) {
			$this->set_nested( 'openingHoursSpecification', $opening_hours );
		}
	}

	/**
	 * Set opening hours specification (new format)
	 *
	 * @param array $hours Opening hours data
	 * @return void
	 */
	private function set_opening_hours( $hours ) {
		if ( empty( $hours ) || ! is_array( $hours ) ) {
			return;
		}

		// If already in OpeningHoursSpecification format, just add
		if ( ! empty( $hours[0] ) && isset( $hours[0]['@type'] ) && 'OpeningHoursSpecification' === $hours[0]['@type'] ) {
			$this->set_nested( 'openingHoursSpecification', $hours );
		}
	}

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

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

		// Address is recommended
		if ( ! isset( $this->schema['address'] ) ) {
			// Not an error, just recommended
		}

		return $errors;
	}
}
