<?php
namespace Components\Models;

class Category extends BaseModel
{
    protected static string $table = 'categories';
    protected static string $primaryKey = 'categories_id';
    protected static string $blueprint = 'category.yaml';

    public static function getNewDefaults(): array
    {
        return [
            'parent_id' => '0',
            'sort_order' => '0',
            'categories_image' => '',
            'date_added' => date('Y-m-d H:i:s'),
            'categories_name' => [],
            'products_id' => [],
        ];
    }

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

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

    public function augmentFormValues(array $values): array
    {
        $id = (int)($values[static::pk()] ?? ($this->{static::pk()} ?? 0));

        if ($id > 0) {
            $rows = CategoryDescription::forCategory($id);
            $names = [];
            foreach ($rows as $lid => $row) {
                $names[(int)$lid] = (string)($row['categories_name'] ?? '');
            }
            $values['categories_name'] = $names;
            $values['products_id'] = ProductToCategory::productIdsForCategory($id);
        } else {
            $values['categories_name'] = [];
            $values['products_id'] = [];
        }

        return $values;
    }

    protected function filterAttributesForSave(array $data): array
    {
        unset($data['categories_name'], $data['products_id']);

        if (array_key_exists('parent_id', $data)) {
            $data['parent_id'] = (string)max(0, (int)$data['parent_id']);
        }

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

        if (array_key_exists('categories_image', $data)) {
            $value = trim((string)$data['categories_image']);
            $data['categories_image'] = ($value === '') ? null : $value;
        }

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

        if (array_key_exists('last_modified', $data)) {
            $value = trim((string)$data['last_modified']);
            $data['last_modified'] = ($value === '') ? null : $value;
        }

        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 = CategoryDescription::table();
        $pk = static::pk();

        $languageId = (int)($filters['language_id'] ?? ($_SESSION['languages_id'] ?? 1));
        $join = " LEFT JOIN " . $descTable . " cd ON " . $table . "." . $pk . " = cd.categories_id AND cd.language_id = " . $languageId;

        $where = "1=1";
        foreach ($filters as $column => $value) {
            if ($column === 'language_id') {
                continue;
            }
            if ($column === 'parent_id') {
                $where .= " AND " . $table . ".parent_id = " . (int)$value;
                continue;
            }
            if ($column === $pk) {
                $where .= " AND " . $table . "." . $pk . " = " . (int)$value;
                continue;
            }

            $where .= " AND " . $table . "." . $column . " = '" . \mh_db_input((string)$value) . "'";
        }

        if ($search !== '' && !empty($searchCols)) {
            $clauses = [];
            foreach ($searchCols as $col) {
                if ($col === 'categories_name') {
                    $clauses[] = "cd.categories_name LIKE '%" . \mh_db_input($search) . "%'";
                } else {
                    $clauses[] = $table . "." . $col . " LIKE '%" . \mh_db_input($search) . "%'";
                }
            }
            $where .= " AND (" . implode(" OR ", $clauses) . ")";
        }

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

        $offset = max(0, ($page - 1) * $perPage);
        $sql = "SELECT " . $table . ".*, cd.categories_name"
            . " FROM " . $table . $join
            . " WHERE " . $where
            . " ORDER BY " . $table . ".parent_id ASC, " . $table . ".sort_order ASC, " . $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 Product[]
     */
    public static function productsForCategory(int $categoryId): array
    {
        $products = [];
        $productIds = static::productIdsForCategory($categoryId);

        foreach ($productIds as $productId) {
            $product = Product::find((int)$productId);
            if ($product instanceof Product) {
                $products[] = $product;
            }
        }

        return $products;
    }

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

        return static::productsForCategory($id);
    }
}
