<?php
namespace Components\Models;

class Product extends BaseModel
{
    protected static string $table = 'TABLE_PRODUCTS';
    protected static string $primaryKey = 'products_id';

    protected static string $blueprint = 'product.yaml';

    public static function isReadOnly(): bool
    {
        return true;
    }

    public static function getNewDefaults(): array
    {
        return [
            'products_quantity' => '0',
            'products_status' => '1',
            'products_tax_class_id' => '0',
            'products_date_added' => date('Y-m-d H:i:s'),
            'products_name' => [],
            'products_description' => [],
            'products_url' => [],
            'categories_id' => [],
        ];
    }

    public function save(): bool
    {
        return false;
    }

    public function delete(): bool
    {
        return false;
    }

    public function manufacturer(): ?Manufacturer
    {
        $manufacturer = $this->belongsTo(Manufacturer::class, 'manufacturers_id', 'manufacturers_id');
        return $manufacturer instanceof Manufacturer ? $manufacturer : null;
    }

    public function augmentFormValues(array $values): array
    {
        $id = (int)($values[static::pk()] ?? 0);
        if ($id > 0) {
            $rows = ProductDescription::forProduct($id);

            $names = [];
            $descriptions = [];
            $urls = [];

            foreach ($rows as $lid => $row) {
                $langId = (int)$lid;
                if ($langId <= 0) {
                    continue;
                }

                $names[$langId] = (string)($row['products_name'] ?? '');
                $descriptions[$langId] = (string)($row['products_description'] ?? '');
                $urls[$langId] = (string)($row['products_url'] ?? '');
            }

            $values['products_name'] = $names;
            $values['products_description'] = $descriptions;
            $values['products_url'] = $urls;
            $values['categories_id'] = ProductToCategory::categoryIdsForProduct($id);
        } else {
            $values['products_name'] = [];
            $values['products_description'] = [];
            $values['products_url'] = [];
            $values['categories_id'] = [];
        }

        return $values;
    }

    protected function filterAttributesForSave(array $data): array
    {
        unset($data['products_name'], $data['products_description'], $data['products_url'], $data['categories_id']);

        if (array_key_exists('products_status', $data)) {
            $data['products_status'] = $this->normalizeToggleToIntString($data['products_status']);
        }

        foreach (['products_quantity', 'products_tax_class_id', 'products_status'] as $intColumn) {
            if (!array_key_exists($intColumn, $data)) {
                continue;
            }

            if ($data[$intColumn] === '' || $data[$intColumn] === null) {
                $data[$intColumn] = '0';
            } else {
                $data[$intColumn] = (string)(int)$data[$intColumn];
            }
        }

        if (array_key_exists('manufacturers_id', $data)) {
            if ($data['manufacturers_id'] === '' || $data['manufacturers_id'] === null) {
                $data['manufacturers_id'] = null;
            } else {
                $data['manufacturers_id'] = (string)(int)$data['manufacturers_id'];
            }
        }

        if (array_key_exists('products_date_added', $data)) {
            $value = trim((string)$data['products_date_added']);
            $data['products_date_added'] = ($value !== '') ? $value : date('Y-m-d H:i:s');
        }

        foreach (['products_last_modified', 'products_date_available'] as $nullableDateColumn) {
            if (!array_key_exists($nullableDateColumn, $data)) {
                continue;
            }

            $value = trim((string)$data[$nullableDateColumn]);
            $data[$nullableDateColumn] = ($value !== '') ? $value : null;
        }

        return parent::filterAttributesForSave($data);
    }

    public function afterSave(array $post): void
    {
        return;
    }

    public static function paginate(int $perPage = 10, int $page = 1, string $search = '', array $searchCols = [], array $filters = []): array
    {
        if (self::isDev()) {
            return ['items' => [], 'total' => 0];
        }

        $table = static::table();
        $descTable = ProductDescription::table();
        $pk = static::pk();
        $langId = (int)($_SESSION['languages_id'] ?? 1);

        $where = "1=1";
        if ($search !== '' && !empty($searchCols)) {
            $clauses = [];
            foreach ($searchCols as $col) {
                if (in_array($col, ['products_name', 'products_description', 'products_url'], true)) {
                    $clauses[] = "pd." . $col . " LIKE '%" . \mh_db_input($search) . "%'";
                } else {
                    $clauses[] = $table . "." . $col . " LIKE '%" . \mh_db_input($search) . "%'";
                }
            }
            $where .= " AND (" . implode(' OR ', $clauses) . ")";
        }

        if (!empty($filters)) {
            foreach ($filters as $col => $val) {
                if ($val === '' || $val === null) {
                    continue;
                }

                if ($col === 'products_status' || $col === 'product_status' || $col === 'status') {
                    $where .= " AND " . $table . ".products_status = '" . \mh_db_input((string)(int)$val) . "'";
                    continue;
                }

                if ($col === 'language_id') {
                    $where .= " AND pd.language_id = '" . \mh_db_input((string)(int)$val) . "'";
                    continue;
                }

                $where .= " AND " . $table . "." . \mh_db_input($col) . " = '" . \mh_db_input((string)$val) . "'";
            }
        }

        $join = " LEFT JOIN " . $descTable . " pd ON (" . $table . "." . $pk . " = pd.products_id AND pd.language_id = " . $langId . ")";

        $countSql = "SELECT COUNT(*) AS total FROM " . $table . $join . " WHERE " . $where;
        $cq = \mh_db_query($countSql);
        $res = \mh_db_fetch_array($cq);
        $total = (int)($res['total'] ?? 0);
        \mh_db_free_result($cq);

        $offset = max(0, ($page - 1) * $perPage);
        $sql = "SELECT " . $table . ".*, pd.products_name, pd.products_description, pd.products_url, pd.language_id FROM " . $table . $join .
            " WHERE " . $where .
            " ORDER BY " . $table . ".products_date_added DESC, " . $table . "." . $pk . " DESC" .
            " LIMIT " . (int)$offset . ", " . (int)$perPage;

        $q = \mh_db_query($sql);
        $items = [];
        while ($row = \mh_db_fetch_array($q)) {
            $items[] = new static($row);
        }
        \mh_db_free_result($q);

        return [
            'items' => $items,
            'total' => $total,
        ];
    }

    /**
     * @return int[]
     */
    public static function categoryIdsForProduct(int $productId): array
    {
        return ProductToCategory::categoryIdsForProduct($productId);
    }

    /**
     * @return int[]
     */
    public static function productIdsForCategory(int $categoryId): array
    {
        return ProductToCategory::productIdsForCategory($categoryId);
    }

    /**
     * @return Category[]
     */
    public static function categoriesForProduct(int $productId): array
    {
        $categories = [];
        $categoryIds = static::categoryIdsForProduct($productId);

        foreach ($categoryIds as $categoryId) {
            $category = Category::find((int)$categoryId);
            if ($category instanceof Category) {
                $categories[] = $category;
            }
        }

        return $categories;
    }

    /**
     * @return Category[]
     */
    public function categories(): array
    {
        $id = (int)($this->attributes[static::pk()] ?? 0);

        return static::categoriesForProduct($id);
    }

    /**
     * @param mixed $value
     */
    protected function normalizeToggleToIntString($value): string
    {
        return ($value === 'on' || $value === '1' || $value === 'True' || $value === true) ? '1' : '0';
    }
}
