<?php

namespace objects;

use classes\db;
use classes\object_property;
use classes\stripe;
use Exception;
use traits\db_object_t;

class stripe_payment_intents_o extends db
{
    use db_object_t;

    public object_property $order_id;
    public object_property $payment_intent_id;
    public object_property $client_secret;
    public object_property $data;
    public object_property $reader_id;
    public object_property $tax_percentage;

    public function structure(): void
    {
        $this->setTable('stripe_payment_intents');
    }

    /**
     * Add a new payment intent
     * @param int $order_id The id of the order
     * @param string $payment_intent_id The id of the payment intent
     * @param string $client_secret The client secret of the payment intent
     * @param mixed $data The data to be added
     * @param int|null $tax_percentage The tax percentage to be added
     * @return void
     * @throws Exception If the object was not created successfully
     */
    public function add(int $order_id, string $payment_intent_id, string $client_secret, mixed $data = null, int $tax_percentage = null): void
    {
        // Convert the data to a JSON string (If it's an object or array)
        if (is_object($data) || is_array($data)) {
            $data = json_encode($data);
        }
        $tmp_id = self::add_object([
            'order_id' => $order_id,
            'payment_intent_id' => $payment_intent_id,
            'client_secret' => $client_secret,
            'data' => $data,
            'tax_percentage' => ($tax_percentage !== null) ? (int)$tax_percentage : 0,
        ]);
        $this->id = $tmp_id;
        self::getObjectProperties();
        self::objectChanged();
    }

    public function getObjectProperties(): void
    {
        $this->order_id = new object_property($this->table, $this->id, 'order_id', 'int', false);
        $this->payment_intent_id = new object_property($this->table, $this->id, 'payment_intent_id', 'string', false);
        $this->client_secret = new object_property($this->table, $this->id, 'client_secret', 'string', false);
        $this->data = new object_property($this->table, $this->id, 'data', 'string', false);
        $this->reader_id = new object_property($this->table, $this->id, 'reader_id', 'int', false);
        $this->tax_percentage = new object_property($this->table, $this->id, 'tax_percentage', 'int', false);
    }

    public function objectChanged(): void
    {
        //TODO: Add cache invalidation
    }

    /**
     * Check if an order has a payment intent
     * @param int $order_id The id of the order
     * @return bool True if the order has a payment intent, false otherwise
     */
    public function doesOrderHavePaymentIntent(int $order_id): bool
    {
        return self::countRowsWhere([
                'order_id' => $order_id,
            ]) > 0;
    }

    /**
     * Get the payment intent id of an order
     * @param int $order_id The id of the order
     * @return self
     * @throws Exception If the object was not selected
     */
    public function selectOrderPaymentIntent(int $order_id): self
    {
        $tmp = self::getFieldsWhere([
            'order_id' => $order_id,
        ],
            ['id']);
        if (count($tmp) > 0) {
            $this->id = $tmp[0]['id'];
            self::getObjectProperties();
            return $this;
        } else {
            throw new Exception('No payment intent found for order id: ' . $order_id);
        }
    }

    /**
     * There's no need to keep track of when the payment intent was created
     * so we just forcefully delete it.
     * @throws Exception If the object was not selected
     * @throws Exception If the object was not deleted successfully
     */
    public function delete(): void
    {
        self::requireSelected();
        self::cancelPaymentIntent();
        self::deletePermanently();
    }

    /**
     * Cancel the payment intent on the reader
     * @throws Exception If the object was not selected
     * @throws Exception If the object was not deleted successfully
     */
    public function cancelPaymentIntent(): void
    {
        self::requireSelected();
        // If a reader id is set, cancel the payment intent on the reader
        if (!empty($this->reader_id->value())) {
            $stripe = new stripe();
            $stripe->readers->sendCancelPaymentIntent($this->reader_id->value(), $this->payment_intent_id->value());
            $this->reader_id->nullify();
            self::objectChanged();
        }
    }
}