<?php
/**
 * Virtual Instance Model
 *
 * Represents a calculated recurring event instance
 *
 * @since   PBOOKING_SINCE
 * @package Nemtly_Booking
 */

namespace NemtlyBooking\Models;

use NemtlyBooking\Core\Event_Creator;

/**
 * Virtual Instance class
 *
 * Represents a single occurrence of a recurring event, calculated on-the-fly
 * from the master event rather than stored in the database. This avoids creating
 * hundreds of duplicate posts for recurring events (see Recurrence_Calculator
 * for the rationale). A virtual instance inherits all properties from its master
 * event but has its own date, and can be individually modified via exceptions.
 *
 * Master data is lazy-loaded and cached per instance to avoid repeated DB hits
 * when rendering lists of recurring occurrences.
 *
 * @since PBOOKING_SINCE
 */
class Virtual_Instance {

    /**
     * Virtual instance ID (master_id_date)
     *
     * @var string
     */
    public $instance_id;

    /**
     * Master event post ID
     *
     * @var int
     */
    public $master_event_id;

    /**
     * Instance date
     *
     * @var string
     */
    public $date;

    /**
     * Cached master event data
     *
     * @var array|null
     */
    private $master_data;

    /**
     * Exception data if this instance is modified
     *
     * @var array|null
     */
    private $exception_data;

    /**
     * Constructor
     *
     * @since PBOOKING_SINCE
     *
     * @param string $instance_id     Virtual instance ID.
     * @param int    $master_event_id Master event post ID.
     * @param string $date            Instance date (Y-m-d).
     */
    public function __construct( $instance_id, $master_event_id, $date ) {
        $this->instance_id     = $instance_id;
        $this->master_event_id = $master_event_id;
        $this->date            = $date;
    }

    /**
     * Get instance data as array (API-ready format)
     *
     * @since PBOOKING_SINCE
     *
     * @return array Instance data.
     */
    public function to_array() {
        $master_data = $this->get_master_data();
        $time        = $master_data['event_time'] ?? '09:00';
        // Merge master event data with instance-specific data
        $instance_data = [
            'id'                 => $this->instance_id,
            'master_event_id'    => $this->master_event_id,
            'is_virtual'         => true,
            'is_recurring'       => true,
            'instance_date'      => $this->date,
            'title'              => [
                'rendered' => $this->get_instance_title(),
            ],
            'content'            => [
                'rendered' => $master_data['content'] ?? '',
            ],
            'status'             => $this->get_instance_status(),
            'event_date'         => $this->date,
            'event_time'         => $time,
            'timezone'           => $master_data['event_timezone'] ?? '',
            'event_duration'     => $master_data['event_duration'] ?? 60,
            'location'           => $master_data['location'] ?? '',
            'max_attendees'      => $master_data['max_attendees'] ?? 0,
            'booking_cutoff'     => $master_data['booking_cutoff'] ?? 0,
            'allow_waitlist'     => $master_data['allow_waitlist'] ?? false,
            'recurrence_pattern' => $master_data['recurrence_pattern'] ?? '',
            'parent_event_id'    => $this->master_event_id,
            'created_at'         => $master_data['created_at'] ?? '',
            'updated_at'         => $master_data['updated_at'] ?? '',
        ];
        // Apply exception data if exists
        if ( $this->has_exception() ) {
            $instance_data = array_merge( $instance_data, $this->get_exception_data() );
        }

        return $instance_data;
    }

    /**
     * Get master event data
     *
     * @since PBOOKING_SINCE
     *
     * @return array Master event data.
     */
    private function get_master_data() {
        if ( null === $this->master_data ) {
            $this->master_data = $this->load_master_data();
        }

        return $this->master_data;
    }

    /**
     * Load master event data from database
     *
     * @since PBOOKING_SINCE
     *
     * @return array Master event data.
     */
    private function load_master_data() {
        $post = get_post( $this->master_event_id );
        if ( ! $post || 'nemtly_event' !== $post->post_type ) {
            return [];
        }

        return [
            'title'              => $post->post_title,
            'content'            => wp_kses_post( wpautop( $post->post_content ) ),
            'status'             => $post->post_status,
            'event_time'         => get_post_meta( $post->ID, Event_Creator::META_EVENT_TIME, true ),
            'event_timezone'     => get_post_meta( $post->ID, Event_Creator::META_EVENT_TIMEZONE, true ),
            'event_duration'     => get_post_meta( $post->ID, Event_Creator::META_EVENT_DURATION, true ),
            'location'           => get_post_meta( $post->ID, Event_Creator::META_LOCATION, true ),
            'max_attendees'      => get_post_meta( $post->ID, Event_Creator::META_MAX_ATTENDEES, true ),
            'booking_cutoff'     => get_post_meta( $post->ID, Event_Creator::META_BOOKING_CUTOFF, true ),
            'allow_waitlist'     => get_post_meta( $post->ID, Event_Creator::META_ALLOW_WAITLIST, true ),
            'recurrence_pattern' => get_post_meta( $post->ID, Event_Creator::META_RECURRENCE_PATTERN, true ),
            'created_at'         => $post->post_date,
            'updated_at'         => $post->post_modified,
        ];
    }

    /**
     * Get instance title with date
     *
     * @since PBOOKING_SINCE
     *
     * @return string Instance title.
     */
    private function get_instance_title() {
        $master_data = $this->get_master_data();
        $base_title  = $master_data['title'] ?? 'Untitled Event';
        if ( $this->has_exception() ) {
            $exception = $this->get_exception_data();
            if ( ! empty( $exception['title'] ) ) {
                return $exception['title'];
            }
        }
        // Add date to title for clarity
        $event_timezone = $master_data['event_timezone'] ?? '';
        try {
            $tz             = new \DateTimeZone( $event_timezone ? $event_timezone : wp_timezone_string() );
            $dt             = new \DateTime( $this->date, $tz );
            $formatted_date = wp_date( get_option( 'date_format' ), $dt->getTimestamp(), $tz );
        } catch ( \Exception $e ) {
            $formatted_date = wp_date( get_option( 'date_format' ), strtotime( $this->date ) );
        }

        return $base_title . ' (' . $formatted_date . ')';
    }

    /**
     * Get instance status (handles exceptions)
     *
     * @since PBOOKING_SINCE
     *
     * @return string Instance status.
     */
    private function get_instance_status() {
        if ( $this->has_exception() ) {
            $exception = $this->get_exception_data();

            return $exception['status'] ?? 'cancelled';
        }
        $master_data = $this->get_master_data();

        return $master_data['status'] ?? 'publish';
    }

    /**
     * Check if this instance has exceptions
     *
     * @since PBOOKING_SINCE
     *
     * @return bool True if has exceptions.
     */
    public function has_exception() {
        $exceptions = get_post_meta( $this->master_event_id, 'nemtly_recurrence_exceptions', true );

        return ! empty( $exceptions[ $this->date ] );
    }

    /**
     * Get exception data for this instance
     *
     * @since PBOOKING_SINCE
     *
     * @return array|null Exception data or null.
     */
    private function get_exception_data() {
        if ( null === $this->exception_data ) {
            $exceptions           = get_post_meta( $this->master_event_id, 'nemtly_recurrence_exceptions', true );
            $this->exception_data = $exceptions[ $this->date ] ?? null;
        }

        return $this->exception_data;
    }

    /**
     * Check if instance is cancelled
     *
     * @since PBOOKING_SINCE
     *
     * @return bool True if cancelled.
     */
    public function is_cancelled() {
        return 'cancelled' === $this->get_instance_status();
    }

    /**
     * Get booking count for this instance
     *
     * @since PBOOKING_SINCE
     *
     * @return int Booking count.
     */
    public function get_booking_count() {
        // TODO: Implement booking count logic
        // This would query bookings table/meta for this specific instance
        return 0;
    }

    /**
     * Check if instance is full
     *
     * @since PBOOKING_SINCE
     *
     * @return bool True if full.
     */
    public function is_full() {
        $master_data   = $this->get_master_data();
        $max_attendees = intval( $master_data['max_attendees'] ?? 0 );
        if ( 0 === $max_attendees ) {
            return false; // Unlimited capacity
        }

        return $this->get_booking_count() >= $max_attendees;
    }

    /**
     * Get DateTime object for this instance
     *
     * @since PBOOKING_SINCE
     *
     * @return \DateTime Instance datetime.
     */
    public function get_datetime() {
        $master_data = $this->get_master_data();
        $time        = $master_data['event_time'] ?? '09:00';

        return new \DateTime( $this->date . ' ' . $time );
    }

    /**
     * Convert instance to REST API response format
     *
     * @since PBOOKING_SINCE
     *
     * @return array REST API formatted data.
     */
    public function prepare_for_response() {
        return apply_filters( 'nemtly_booking_virtual_instance_response', $this->to_array(), $this );
    }

    /**
     * Static method to create instance from master event and date
     *
     * @since PBOOKING_SINCE
     *
     * @param int    $master_event_id Master event ID.
     * @param string $date            Instance date (Y-m-d).
     *
     * @return Virtual_Instance Instance object.
     */
    public static function create( $master_event_id, $date ) {
        $instance_id = $master_event_id . '_' . $date;

        return new self( $instance_id, $master_event_id, $date );
    }
}
