<?php
/**
 * DESCRIPTION: Booking model representing a single booking record. Implements
 * Payable for Stripe payment integration. Stores attendee info, status, and metadata.
 *
 * @package NemtlyBooking\Models
 */

namespace NemtlyBooking\Models;

use NemtlyBooking\Core\Status;
use NemtlyBooking\Interfaces\Payable;

class Booking implements Payable {
    /**
     * Booking ID
     *
     * @var int
     */
    private $id;

    /**
     * Event ID this booking belongs to
     *
     * @var int
     */
    private $event_id;

    /**
     * User ID (null for guest bookings)
     *
     * @var int|null
     */
    private $user_id;

    /**
     * Unique booking reference UUID
     *
     * @var string
     */
    private $booking_uuid;

    /**
     * Booking status
     *
     * @var string
     */
    private $booking_status;

    /**
     * Attendee name
     *
     * @var string
     */
    private $attendee_name;

    /**
     * Attendee email
     *
     * @var string
     */
    private $attendee_email;

    /**
     * Attendee phone (optional)
     *
     * @var string|null
     */
    private $attendee_phone;

    /**
     * Booking date
     *
     * @var string
     */
    private $booking_date;

    /**
     * Booking start time
     *
     * @var string|null
     */
    private $booking_start;

    /**
     * Booking end time
     *
     * @var string|null
     */
    private $booking_end;

    /**
     * Additional booking metadata
     *
     * @var array
     */
    private $booking_meta;

    /**
     * Creation timestamp
     *
     * @var string
     */
    private $created_at;

    /**
     * Last update timestamp
     *
     * @var string
     */
    private $updated_at;

    /**
     * Constructor
     *
     * @param array $args Booking data.
     */
    public function __construct( $args = [] ) {
        $this->id             = ! empty( $args['id'] ) ? (int) $args['id'] : 0;
        $this->event_id       = ! empty( $args['event_id'] ) ? (int) $args['event_id'] : 0;
        $this->user_id        = ! empty( $args['user_id'] ) ? (int) $args['user_id'] : null;
        $this->booking_uuid   = ! empty( $args['booking_uuid'] ) ? $args['booking_uuid'] : $this->generate_uuid();
        $this->booking_status = ! empty( $args['booking_status'] ) ? $args['booking_status'] : Status::BOOKING_PENDING;
        $this->attendee_name  = ! empty( $args['attendee_name'] ) ? $args['attendee_name'] : '';
        $this->attendee_email = ! empty( $args['attendee_email'] ) ? $args['attendee_email'] : '';
        $this->attendee_phone = ! empty( $args['attendee_phone'] ) ? $args['attendee_phone'] : null;
        $this->booking_date   = ! empty( $args['booking_date'] ) ? $args['booking_date'] : '';
        $this->booking_start  = ! empty( $args['booking_start'] ) ? $args['booking_start'] : null;
        $this->booking_end    = ! empty( $args['booking_end'] ) ? $args['booking_end'] : null;
        $this->booking_meta   = ! empty( $args['booking_meta'] ) ? $args['booking_meta'] : [];
        $this->created_at     = ! empty( $args['created_at'] ) ? $args['created_at'] : gmdate( 'Y-m-d H:i:s' );
        $this->updated_at     = ! empty( $args['updated_at'] ) ? $args['updated_at'] : gmdate( 'Y-m-d H:i:s' );
    }

    /**
     * Generate UUID v4
     *
     * @return string UUID v4 string.
     */
    private function generate_uuid(): string {
        return sprintf(
            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            wp_rand( 0, 0xffff ),
            wp_rand( 0, 0xffff ),
            wp_rand( 0, 0xffff ),
            wp_rand( 0, 0x0fff ) | 0x4000,
            wp_rand( 0, 0x3fff ) | 0x8000,
            wp_rand( 0, 0xffff ),
            wp_rand( 0, 0xffff ),
            wp_rand( 0, 0xffff )
        );
    }

    /**
     * Get booking ID
     *
     * @return int
     */
    public function get_id(): int {
        return $this->id;
    }

    /**
     * Get event ID
     *
     * @return int
     */
    public function get_event_id(): int {
        return $this->event_id;
    }

    /**
     * Set event ID
     *
     * @param int $event_id Event ID.
     */
    public function set_event_id( int $event_id ): void {
        $this->event_id = $event_id;
    }

    /**
     * Get user ID
     *
     * @return int|null
     */
    public function get_user_id(): ?int {
        return $this->user_id;
    }

    /**
     * Set user ID
     *
     * @param int|null $user_id User ID.
     */
    public function set_user_id( ?int $user_id ): void {
        $this->user_id = $user_id;
    }

    /**
     * Get booking UUID
     *
     * @return string
     */
    public function get_booking_uuid(): string {
        return $this->booking_uuid;
    }

    /**
     * Get booking status
     *
     * @return string
     */
    public function get_booking_status(): string {
        return $this->booking_status;
    }

    /**
     * Set booking status
     *
     * @param string $status Booking status.
     */
    public function set_booking_status( string $status ): void {
        $allowed_statuses = Status::booking_statuses();
        if ( in_array( $status, $allowed_statuses, true ) ) {
            $this->booking_status = $status;
        }
    }

    /**
     * Get customer name
     *
     * @return string
     */
    public function get_attendee_name(): string {
        return $this->attendee_name;
    }

    /**
     * Set attendee name
     *
     * @param string $name Attendee name.
     */
    public function set_attendee_name( string $name ): void {
        $this->attendee_name = sanitize_text_field( $name );
    }

    /**
     * Get attendee email
     *
     * @return string
     */
    public function get_attendee_email(): string {
        return $this->attendee_email;
    }

    /**
     * Set attendee email
     *
     * @param string $email Attendee email.
     */
    public function set_attendee_email( string $email ): void {
        $this->attendee_email = sanitize_email( $email );
    }

    /**
     * Get attendee phone
     *
     * @return string|null
     */
    public function get_attendee_phone(): ?string {
        return $this->attendee_phone;
    }

    /**
     * Set attendee phone
     *
     * @param string|null $phone Attendee phone.
     */
    public function set_attendee_phone( ?string $phone ): void {
        $this->attendee_phone = $phone ? sanitize_text_field( $phone ) : null;
    }

    /**
     * Get booking date
     *
     * @return string
     */
    public function get_booking_date(): string {
        return $this->booking_date;
    }

    /**
     * Set booking date
     *
     * @param string $date Booking date.
     */
    public function set_booking_date( string $date ): void {
        $this->booking_date = sanitize_text_field( $date );
    }

    /**
     * Get booking start time
     *
     * @return string|null
     */
    public function get_booking_start(): ?string {
        return $this->booking_start;
    }

    /**
     * Set booking start time
     *
     * @param string|null $start Start time.
     */
    public function set_booking_start( ?string $start ): void {
        $this->booking_start = $start ? sanitize_text_field( $start ) : null;
    }

    /**
     * Get booking end time
     *
     * @return string|null
     */
    public function get_booking_end(): ?string {
        return $this->booking_end;
    }

    /**
     * Set booking end time
     *
     * @param string|null $end End time.
     */
    public function set_booking_end( ?string $end ): void {
        $this->booking_end = $end ? sanitize_text_field( $end ) : null;
    }

    /**
     * Get booking metadata
     *
     * @return array
     */
    public function get_booking_meta(): array {
        return $this->booking_meta;
    }

    /**
     * Set booking metadata
     *
     * @param array $meta Booking metadata.
     */
    public function set_booking_meta( $meta ): void {
        $this->booking_meta = is_array( $meta ) ? $meta : [];
    }

    /**
     * Get creation timestamp
     *
     * @return string
     */
    public function get_created_at(): string {
        return $this->created_at;
    }

    /**
     * Get update timestamp
     *
     * @return string
     */
    public function get_updated_at(): string {
        return $this->updated_at;
    }

    /**
     * Update the updated_at timestamp
     */
    public function touch(): void {
        $this->updated_at = gmdate( 'Y-m-d H:i:s' );
    }

    /**
     * Convert booking to array
     *
     * @return array
     */
    public function to_array(): array {
        return [
            'id'             => $this->id,
            'event_id'       => $this->event_id,
            'user_id'        => $this->user_id,
            'booking_uuid'   => $this->booking_uuid,
            'booking_status' => $this->booking_status,
            'attendee_name'  => $this->attendee_name,
            'attendee_email' => $this->attendee_email,
            'attendee_phone' => $this->attendee_phone,
            'booking_date'   => $this->booking_date,
            'booking_start'  => $this->booking_start,
            'booking_end'    => $this->booking_end,
            'booking_meta'   => $this->booking_meta,
            'created_at'     => $this->created_at,
            'updated_at'     => $this->updated_at,
        ];
    }

    /**
     * Check if booking is confirmed
     *
     * @return bool
     */
    public function is_confirmed(): bool {
        return Status::BOOKING_CONFIRMED === $this->booking_status;
    }

    /**
     * Check if booking is pending
     *
     * @return bool
     */
    public function is_pending(): bool {
        return Status::BOOKING_PENDING === $this->booking_status;
    }

    /**
     * Check if booking is cancelled
     *
     * @return bool
     */
    public function is_cancelled(): bool {
        return Status::BOOKING_CANCELLED === $this->booking_status;
    }

    /**
     * Check if booking is guest booking
     *
     * @return bool
     */
    public function is_guest_booking(): bool {
        return null === $this->user_id;
    }

    /**
     * Get the type of the payable entity.
     *
     * @return string
     */
    public function get_type(): string {
        return 'booking';
    }

    /**
     * Get the amount to be paid.
     *
     * @return float
     */
    public function get_payment_amount(): float {
        // TODO: This should ideally come from the Event price or a calculated total.
        // For now, returning dummy or meta value if exists, or 0.
        return isset( $this->booking_meta['payment_amount'] ) ? (float) $this->booking_meta['payment_amount'] : 0.0;
    }

    /**
     * Get the currency code.
     *
     * @return string
     */
    public function get_payment_currency(): string {
        return isset( $this->booking_meta['currency'] ) ? $this->booking_meta['currency'] : 'USD';
    }

    /**
     * Get a description for the payment.
     *
     * @return string
     */
    public function get_payment_description(): string {
        return sprintf(
            /* translators: %d: Booking ID */
            esc_html__( 'Booking #%d', 'nemtly-booking' ),
            $this->id
        );
    }
}
