<?php

namespace objects;

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

class motorapi_lookups_o extends db
{
    use db_object_t;

    public object_property $license_plate;
    public object_property $result;
    public object_property $endpoint;
    public object_property $created_at;


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

    /**
     * Add a motorapi lookup
     * @param string $license_plate
     * @param string $result
     * @param string $endpoint
     * @return void
     * @throws Exception If the object was not created successfully
     */
    public function add(string $license_plate, string $result, string $endpoint): void
    {
        global /** @var db $db */
        $db;
        // Sanitize the input
        $license_plate = $db->escape_string($license_plate);
        $result = $db->escape_string($result);
        $endpoint = $db->escape_string($endpoint);
        // Add the object
        $tmp_id = self::add_object([
            'license_plate' => $license_plate,
            'result' => $result,
            'endpoint' => $endpoint
        ]);
        $this->id = $tmp_id;
        self::getObjectProperties();
        self::objectChanged();
    }

    public function getObjectProperties(): void
    {
        $this->license_plate = new object_property($this->table, $this->id, 'license_plate', 'string', false);
        $this->result = new object_property($this->table, $this->id, 'result', 'string', false);
        $this->endpoint = new object_property($this->table, $this->id, 'endpoint', 'string', false);
        $this->created_at = new object_property($this->table, $this->id, 'created_at', 'datetime', false);
    }

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

    /**
     * Get the amount of motorapi lookups created today
     * @return int
     */
    public function getTodayCount(): int
    {
        global /** @var db $db */
        $db;
        $sql = 'SELECT COUNT(*) FROM ' . $this->table . ' WHERE DATE(created_at) = CURDATE()';
        $result = $db->query($sql);
        return (int)$result->fetch_row()[0];
    }

    public function asArray(): array
    {
        return [
            'id' => (int)$this->id,
            'license_plate' => (string)$this->license_plate->value(),
            'result' => (string)$this->result->value(),
            'endpoint' => (string)$this->endpoint->value(),
            'created_at' => (string)$this->created_at->value(),
        ];
    }

    /**
     * Is the license plate in the cache?
     * @param string $license_plate
     * @return bool
     * @throws Exception If the license plate is not valid
     */
    public function isCached(string $license_plate): bool
    {
        global /** @var db $db */
        $db;
        if (!self::validateLicensePlateFormat($license_plate)) {
            throw new Exception('The license plate is not valid.');
        }
        $result = self::getFieldsWhere(['license_plate' => $license_plate], ['id']);
        return !empty($result);
    }

    /**
     * Validate the format of a license plate
     * @note This simply checks if the license plate is in the format of two letters followed by four or five numbers.
     * @note This does not check if the license plate is actually valid.
     * @param string $license_plate
     * @return bool
     */
    public static function validateLicensePlateFormat(string $license_plate): bool
    {
        return (bool)preg_match('/^[A-Z]{2}[0-9]{4,5}$/', $license_plate);
    }

    /**
     * Get the (latest) cached result for a license plate
     * @param string $license_plate
     * @return object|null The motorapi_lookups_o object or null if not found
     * @throws Exception If the license plate is not valid or the response is not cached
     */
    public function getCachedResult(string $license_plate): ?object
    {
        global /** @var db $db */
        $db;
        if (!self::validateLicensePlateFormat($license_plate)) {
            throw new Exception('The license plate is not valid.');
        }
        $result = self::getFieldsWhere(['license_plate' => $license_plate], ['id', 'result', 'endpoint', 'created_at']);
        if (!$result) {
            return null;
        }
        // Get the latest result
        $latest = array_pop($result);
        $this->id = $latest['id'];
        self::getObjectProperties();
        return $this;
    }

    /**
     * Get all cached results with the "result" field containing a specific substring(s)
     * @param string|array $substrings
     * @return array An array of motorapi_lookups_o objects
     * @throws Exception If no results are found
     */
    public function getCachedResultsBySubstring(string|array $substrings): array
    {
        global /** @var db $db */
        $db;
        if (is_string($substrings)) {
            $substrings = [$substrings];
        }
        $where_clauses = [];
        foreach ($substrings as $substring) {
            $escaped_substring = $db->escape_string($substring);
            $where_clauses[] = "result LIKE '%$escaped_substring%'";
        }
        $where_sql = implode(' OR ', $where_clauses);
        $sql = "SELECT id FROM " . $this->table . " WHERE $where_sql";
        $result = $db->query($sql);
        if ($result->num_rows === 0) {
            throw new Exception('No results found.');
        }
        $objects = [];
        while ($row = $result->fetch_assoc()) {
            $obj = new self();
            $obj->id = $row['id'];
            $obj->getObjectProperties();
            $objects[] = $obj;
        }
        return $objects;
    }

}