<?php
/**
 * DESCRIPTION: Event repository for persisting events as nemtly_event CPT posts.
 * Handles CRUD via wp_insert_post/wp_update_post and post meta for event fields.
 *
 * @package NemtlyBooking\Repositories
 */

namespace NemtlyBooking\Repositories;

use NemtlyBooking\Models\Event;
use NemtlyBooking\Core\Event_Creator;

class Event_Repository {

    /**
     * Create a new event
     *
     * @param Event $event The event to create.
     *
     * @return Event|false
     */
    public function create( Event $event ) {
        $post_id = \wp_insert_post(
            [
                'post_type'    => 'nemtly_event',
                'post_title'   => $event->get_title(),
                'post_content' => $event->get_description(),
                'post_status'  => $event->get_status(),
                'meta_input'   => [
                    Event_Creator::META_EVENT_DATE         => $event->get_date(),
                    Event_Creator::META_EVENT_TIME         => $event->get_time(),
                    Event_Creator::META_EVENT_DATE_UTC     => $event->get_date_utc(),
                    Event_Creator::META_EVENT_TIME_UTC     => $event->get_time_utc(),
                    Event_Creator::META_EVENT_TIMEZONE     => $event->get_timezone(),
                    Event_Creator::META_EVENT_END_DATE     => $event->get_end_date(),
                    Event_Creator::META_EVENT_END_TIME     => $event->get_end_time(),
                    Event_Creator::META_EVENT_DURATION     => $event->get_duration(),
                    Event_Creator::META_LOCATION           => $event->get_location(),
                    Event_Creator::META_MAX_ATTENDEES      => $event->get_max_attendees(),
                    Event_Creator::META_BOOKING_CUTOFF     => $event->get_booking_cutoff(),
                    Event_Creator::META_ALLOW_WAITLIST     => $event->get_allow_waitlist(),
                    Event_Creator::META_RECURRENCE_PATTERN => $event->get_recurrence_pattern(),
                    Event_Creator::META_RECURRENCE_COUNT   => $event->get_recurrence_count(),
                    Event_Creator::META_RECURRENCE_END     => $event->get_recurrence_end(),
                    Event_Creator::META_PARENT_EVENT_ID    => $event->get_parent_event_id(),
                    Event_Creator::META_IS_RECURRING       => $event->get_is_recurring(),
                    Event_Creator::META_FEATURED_IMAGE     => $event->get_featured_image(),
                    Event_Creator::META_PRICE              => $event->get_price(),
                    Event_Creator::META_BUFFER_BEFORE      => $event->get_buffer_before(),
                    Event_Creator::META_BUFFER_AFTER       => $event->get_buffer_after(),
                    Event_Creator::META_EVENT_TYPE         => $event->get_event_type(),
                    Event_Creator::META_AVAILABILITY       => wp_json_encode( $event->get_availability() ),
                    Event_Creator::META_STYLING            => wp_json_encode( $event->get_styling() ),
                ],
            ]
        );
        if ( \is_wp_error( $post_id ) ) {
            return false;
        }

        return $this->find( $post_id );
    }

    /**
     * Find event by ID
     *
     * @param int $id The event ID to find.
     *
     * @return Event|null
     */
    public function find( int $id ): ?Event {
        $post = \get_post( $id );
        if ( ! $post || 'nemtly_event' !== $post->post_type ) {
            return null;
        }

        return new Event(
            [
                'id'                 => $post->ID,
                'title'              => $post->post_title,
                'description'        => $post->post_content,
                'date'               => \get_post_meta( $post->ID, Event_Creator::META_EVENT_DATE, true ),
                'time'               => \get_post_meta( $post->ID, Event_Creator::META_EVENT_TIME, true ),
                'date_utc'           => \get_post_meta( $post->ID, Event_Creator::META_EVENT_DATE_UTC, true ),
                'time_utc'           => \get_post_meta( $post->ID, Event_Creator::META_EVENT_TIME_UTC, true ),
                'timezone'           => \get_post_meta( $post->ID, Event_Creator::META_EVENT_TIMEZONE, true ),
                'end_date'           => \get_post_meta( $post->ID, Event_Creator::META_EVENT_END_DATE, true ),
                'end_time'           => \get_post_meta( $post->ID, Event_Creator::META_EVENT_END_TIME, true ),
                'end_date_utc'       => \get_post_meta( $post->ID, Event_Creator::META_EVENT_END_DATE_UTC, true ),
                'end_time_utc'       => \get_post_meta( $post->ID, Event_Creator::META_EVENT_END_TIME_UTC, true ),
                '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 ),
                'recurrence_count'   => \get_post_meta( $post->ID, Event_Creator::META_RECURRENCE_COUNT, true ),
                'recurrence_end'     => \get_post_meta( $post->ID, Event_Creator::META_RECURRENCE_END, true ),
                'parent_event_id'    => \get_post_meta( $post->ID, Event_Creator::META_PARENT_EVENT_ID, true ),
                'is_recurring'       => \get_post_meta( $post->ID, Event_Creator::META_IS_RECURRING, true ),
                'price'              => \get_post_meta( $post->ID, Event_Creator::META_PRICE, true ),
                'buffer_before'      => \get_post_meta( $post->ID, Event_Creator::META_BUFFER_BEFORE, true ),
                'buffer_after'       => \get_post_meta( $post->ID, Event_Creator::META_BUFFER_AFTER, true ),
                'event_type'         => \get_post_meta( $post->ID, Event_Creator::META_EVENT_TYPE, true ),
                'availability'       => json_decode( \get_post_meta( $post->ID, Event_Creator::META_AVAILABILITY, true ) ? \get_post_meta( $post->ID, Event_Creator::META_AVAILABILITY, true ) : '[]', true ),
                'styling'            => json_decode( \get_post_meta( $post->ID, Event_Creator::META_STYLING, true ) ? \get_post_meta( $post->ID, Event_Creator::META_STYLING, true ) : '[]', true ),

                'status'             => $post->post_status,
            ]
        );
    }

    /**
     * Update an event
     *
     * @param Event $event The event to update.
     *
     * @return Event|false
     */
    public function update( Event $event ) {
        $result = \wp_update_post(
            [
                'ID'           => $event->get_id(),
                'post_title'   => $event->get_title(),
                'post_content' => $event->get_description(),
                'post_status'  => $event->get_status(),
            ]
        );
        if ( \is_wp_error( $result ) ) {
            return false;
        }

        // Update meta fields
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_DATE, $event->get_date() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_TIME, $event->get_time() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_DATE_UTC, $event->get_date_utc() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_TIME_UTC, $event->get_time_utc() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_TIMEZONE, $event->get_timezone() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_END_DATE, $event->get_end_date() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_END_TIME, $event->get_end_time() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_END_DATE_UTC, $event->get_end_date_utc() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_END_TIME_UTC, $event->get_end_time_utc() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_DURATION, $event->get_duration() );
        \update_post_meta( $event->get_id(), Event_Creator::META_LOCATION, $event->get_location() );
        \update_post_meta( $event->get_id(), Event_Creator::META_MAX_ATTENDEES, $event->get_max_attendees() );
        \update_post_meta( $event->get_id(), Event_Creator::META_BOOKING_CUTOFF, $event->get_booking_cutoff() );
        \update_post_meta( $event->get_id(), Event_Creator::META_ALLOW_WAITLIST, $event->get_allow_waitlist() );
        \update_post_meta( $event->get_id(), Event_Creator::META_RECURRENCE_PATTERN, $event->get_recurrence_pattern() );
        \update_post_meta( $event->get_id(), Event_Creator::META_RECURRENCE_COUNT, $event->get_recurrence_count() );
        \update_post_meta( $event->get_id(), Event_Creator::META_RECURRENCE_END, $event->get_recurrence_end() );
        \update_post_meta( $event->get_id(), Event_Creator::META_PARENT_EVENT_ID, $event->get_parent_event_id() );
        \update_post_meta( $event->get_id(), Event_Creator::META_IS_RECURRING, $event->get_is_recurring() );
        \update_post_meta( $event->get_id(), Event_Creator::META_PRICE, $event->get_price() );
        \update_post_meta( $event->get_id(), Event_Creator::META_BUFFER_BEFORE, $event->get_buffer_before() );
        \update_post_meta( $event->get_id(), Event_Creator::META_BUFFER_AFTER, $event->get_buffer_after() );
        \update_post_meta( $event->get_id(), Event_Creator::META_EVENT_TYPE, $event->get_event_type() );
        \update_post_meta( $event->get_id(), Event_Creator::META_AVAILABILITY, wp_json_encode( $event->get_availability() ) );
        \update_post_meta( $event->get_id(), Event_Creator::META_STYLING, wp_json_encode( $event->get_styling() ) );

        return $this->find( $event->get_id() );
    }

    /**
     * Delete an event
     *
     * @param int $id The event ID to delete.
     *
     * @return bool
     */
    public function delete( int $id ): bool {
        $result = wp_delete_post( $id, true );

        return ! is_wp_error( $result ) && false !== $result;
    }

    /**
     * Find all events
     *
     * @param array $args Query arguments.
     *
     * @return Event[]
     */
    public function find_all( array $args = [] ): array {
        $defaults = [
            'post_type'              => 'nemtly_event',
            'post_status'            => 'publish',
            'posts_per_page'         => - 1,
            'orderby'                => 'meta_value',
            'meta_key'               => Event_Creator::META_EVENT_DATE_UTC,
            'order'                  => 'ASC',
            'cache_results'          => true,
            'update_post_meta_cache' => true,
            'update_post_term_cache' => false,
        ];

        $args   = \wp_parse_args( $args, $defaults );
        $posts  = \get_posts( $args );
        $events = [];

        foreach ( $posts as $post ) {
            $events[] = new Event(
                [
                    'id'                 => $post->ID,
                    'title'              => $post->post_title,
                    'description'        => $post->post_content,
                    'date'               => get_post_meta( $post->ID, Event_Creator::META_EVENT_DATE, true ),
                    'time'               => get_post_meta( $post->ID, Event_Creator::META_EVENT_TIME, true ),
                    'date_utc'           => get_post_meta( $post->ID, Event_Creator::META_EVENT_DATE_UTC, true ),
                    'time_utc'           => get_post_meta( $post->ID, Event_Creator::META_EVENT_TIME_UTC, true ),
                    'timezone'           => get_post_meta( $post->ID, Event_Creator::META_EVENT_TIMEZONE, true ),
                    'end_date'           => get_post_meta( $post->ID, Event_Creator::META_EVENT_END_DATE, true ),
                    'end_time'           => get_post_meta( $post->ID, Event_Creator::META_EVENT_END_TIME, true ),
                    'end_date_utc'       => get_post_meta( $post->ID, Event_Creator::META_EVENT_END_DATE_UTC, true ),
                    'end_time_utc'       => get_post_meta( $post->ID, Event_Creator::META_EVENT_END_TIME_UTC, true ),
                    '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 ),
                    'recurrence_count'   => get_post_meta( $post->ID, Event_Creator::META_RECURRENCE_COUNT, true ),
                    'recurrence_end'     => get_post_meta( $post->ID, Event_Creator::META_RECURRENCE_END, true ),
                    'parent_event_id'    => get_post_meta( $post->ID, Event_Creator::META_PARENT_EVENT_ID, true ),
                    'is_recurring'       => get_post_meta( $post->ID, Event_Creator::META_IS_RECURRING, true ),
                    'price'              => get_post_meta( $post->ID, Event_Creator::META_PRICE, true ),
                    'buffer_before'      => get_post_meta( $post->ID, Event_Creator::META_BUFFER_BEFORE, true ),
                    'buffer_after'       => get_post_meta( $post->ID, Event_Creator::META_BUFFER_AFTER, true ),
                    'event_type'         => get_post_meta( $post->ID, Event_Creator::META_EVENT_TYPE, true ),
                    'availability'       => json_decode( get_post_meta( $post->ID, Event_Creator::META_AVAILABILITY, true ) ? get_post_meta( $post->ID, Event_Creator::META_AVAILABILITY, true ) : '[]', true ),
                    'styling'            => json_decode( get_post_meta( $post->ID, Event_Creator::META_STYLING, true ) ? get_post_meta( $post->ID, Event_Creator::META_STYLING, true ) : '[]', true ),
                    'status'             => $post->post_status,
                ]
            );
        }

        return $events;
    }

    /**
     * Find events by date range
     *
     * @param string $start_date The start date of the range.
     * @param string $end_date   The end date of the range.
     *
     * @return Event[]
     */
    public function find_by_date_range( string $start_date, string $end_date ): array {
        $args = [
            'meta_query'             => [
                [
                    'key'     => Event_Creator::META_EVENT_DATE_UTC,
                    'value'   => [ $start_date, $end_date ],
                    'compare' => 'BETWEEN',
                    'type'    => 'DATE',
                ],
            ],
            'cache_results'          => true,
            'update_post_meta_cache' => true,
            'update_post_term_cache' => false,
        ];

        return $this->find_all( $args );
    }
}
