<?php

declare(strict_types=1);

namespace Plugin\tnt_stabila_shop\src\Abstracts;

use Plugin\tnt_stabila_shop\src\Helper\ShopRuntime;
use Plugin\tnt_stabila_shop\src\Interfaces\ModelInterface;

abstract class AbstractModel implements ModelInterface
{
    public static function getPrimaryKey(): string
    {
        return \array_keys(static::getSchema())[0] ?? 'id';
    }

    public static function getTotalEntriesQuery(): string
    {
        return 'SELECT COUNT(*) AS cnt FROM ' . static::getTable();
    }

    public static function getPaginatedQuery(
        int $currentPage,
        int $pageSize,
        string $where,
        string $sort = ''
    ): string {
        $offset = ($currentPage - 1) * $pageSize;
        $limit  = $pageSize;

        $result = 'SELECT * FROM ' . static::getTable() . ' WHERE ' . $where;
        if ($sort !== '') {
            $result .= ' ORDER BY ' . $sort;
        }
        $result .= ' LIMIT ' . $offset . ', ' . $limit;

        return $result;
    }

    public static function transformData(object $data): object
    {
        $result = [];
        $schema = static::getSchema();
        foreach ((array)$data as $field => $value) {
            if (isset($schema[$field]) === false) {
                continue;
            }
            $result[$field] = match ($schema[$field]) {
                'int'      => self::toInt($value),
                'float'    => self::toFloat($value),
                'bool'     => self::toBool($value),
                'datetime' => self::toDateTime($value),
                default    => $value,
            };
        }

        return (object)$result;
    }

    /**
     * @return list<string>
     */
    public static function getSearchableFields(): array
    {
        return \array_keys(static::getSchema());
    }

    public static function toInt(string $value): int
    {
        return (int)$value;
    }

    public static function toFloat(string $value): float
    {
        return (float)$value;
    }

    public static function toBool(string $value): bool
    {
        return (bool)$value;
    }

    private static function toDateTime(string $value): \DateTime
    {
        try {
            $result = new \DateTime($value, ShopRuntime::timezone());
        } catch (\DateException) {
            $result = new \DateTime();
        }

        return $result;
    }
}
