<?php

namespace Twnt4All\Support;

use Twnt4All\Engine\Contract\LockInterface;

/**
 * Class WooOrderLock
 * @package Twnt4All\Support
 * @since 6.0.0
 */
class WooOrderLock implements LockInterface
{
    const LOCK_PREFIX = '_' . T4A_PREFIX . '_lock_';

    /** @var \WC_order */
    private $order;

    /** @var int|string */
    private $order_id;

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

    /** @var mixed */
    private $value;

    /**
     * DB_Lock constructor.
     *
     * @param int|string $order_id
     * @param string $name
     * @param mixed $value
     * @since 3.1.0
     *
     */
    public function __construct( $order_id, $name, $value )
    {
        $this->order_id = $order_id;
        $this->name     = $name;
        $this->value    = $value;
    }

    /**
     * Acquires the lock and returns it. Returns null if lock could not be acquired.
     *
     * @return WooOrderLock|null
     * @since 3.1.0
     *
     */
    public function acquire()
    {
        $this->order = wc_get_order( $this->order_id );

        // WC path (default).
        if ( $this->order ) {
            if ( $this->value !== $this->order->get_meta( static::LOCK_PREFIX . $this->name, true ) ) {
                $this->order->update_meta_data( static::LOCK_PREFIX . $this->name, $this->value );
                $this->order->update_meta_data( static::LOCK_PREFIX . $this->name . '-timestamp', time() );
                $this->order->save();
                return new static( $this->order_id, $this->name, $this->value );
            }
            return null;
        }

        // Pay4All Form fallback: wc_get_order returns false for our p4all_order
        // CPT, so persist the lock flag directly through the post-meta API. Same
        // semantics (compare-and-set), just one layer below WC_Order.
        if ( get_post( $this->order_id ) ) {
            $current = get_post_meta( $this->order_id, static::LOCK_PREFIX . $this->name, true );
            if ( $this->value !== $current ) {
                update_post_meta( $this->order_id, static::LOCK_PREFIX . $this->name, $this->value );
                update_post_meta( $this->order_id, static::LOCK_PREFIX . $this->name . '-timestamp', time() );
                return new static( $this->order_id, $this->name, $this->value );
            }
        }

        return null;
    }

    /**
     * @since 3.1.0
     *
     * Releases the lock.
     */
    public function release()
    {
        $this->order = wc_get_order( $this->order_id );
        if ( $this->order ) {
            WooBridge::delete_order_meta( $this->order, static::LOCK_PREFIX . $this->name, $this->value, false );
            WooBridge::delete_order_meta( $this->order, static::LOCK_PREFIX . $this->name . '-timestamp' );
            return;
        }
        // Form fallback.
        delete_post_meta( $this->order_id, static::LOCK_PREFIX . $this->name );
        delete_post_meta( $this->order_id, static::LOCK_PREFIX . $this->name . '-timestamp' );
    }

    /**
     * @return mixed
     *
     * @since 4.0.2
     */
    public function is_free()
    {
        $this->order = wc_get_order( $this->order_id );
        if ( $this->order ) {
            return ! $this->order->get_meta( static::LOCK_PREFIX . $this->name, true );
        }
        // Form fallback.
        return ! get_post_meta( $this->order_id, static::LOCK_PREFIX . $this->name, true );
    }

    /**
     * @return mixed
     *
     * @since 5.0.0
     */
    public function get_timestamp()
    {
        $this->order = wc_get_order( $this->order_id );
        if ( $this->order ) {
            return $this->order->get_meta( static::LOCK_PREFIX . $this->name . '-timestamp', true );
        }
        // Form fallback.
        $ts = get_post_meta( $this->order_id, static::LOCK_PREFIX . $this->name . '-timestamp', true );
        return $ts !== '' ? $ts : null;
    }
}