<?php

namespace app\models;

use yii\db\ActiveRecord;

/**
 * @property int    $id
 * @property string $category_id
 * @property string $parent_id
 * @property string $category_name
 * @property string $is_active
 * @property string $created_at
 * @property string $updated_at
 */
class Category extends ActiveRecord
{
    public static function tableName(): string
    {
        return '{{%category}}';
    }

    public function rules(): array
    {
        return [
            [['category_id', 'category_name'], 'required'],
            [['category_id'], 'string', 'max' => 50],
            [['category_id'], 'match', 'pattern' => '/^[A-Za-z0-9_\-]+$/',
                'message' => 'Category ID may only contain letters, numbers, hyphens and underscores.'],
            [['parent_id'], 'string', 'max' => 50],
            [['category_name'], 'string', 'max' => 200],
            [['category_id'], 'unique'],
            [['is_active'], 'in', 'range' => ['Y', 'N']],
            [['parent_id', 'is_active'], 'safe'],
            [['parent_id'], 'validateParentId'],
        ];
    }

    public function validateParentId($attribute): void
    {
        $parentId = $this->$attribute;
        if (empty($parentId)) {
            return;
        }
        if ($parentId === $this->category_id) {
            $this->addError($attribute, 'A category cannot be its own parent.');
            return;
        }
        $exists = self::find()->where(['category_id' => $parentId])->exists();
        if (!$exists) {
            $this->addError($attribute, "Parent ID '{$parentId}' does not exist.");
        }
    }

    public function attributeLabels(): array
    {
        return [
            'id'            => 'ID',
            'category_id'   => 'Category ID',
            'parent_id'     => 'Parent ID',
            'category_name' => 'Category Name',
            'is_active'     => 'Status',
            'created_at'    => 'Created',
            'updated_at'    => 'Updated',
        ];
    }

    public function getParent(): \yii\db\ActiveQuery
    {
        return $this->hasOne(self::class, ['category_id' => 'parent_id']);
    }

    public function getChildren(): \yii\db\ActiveQuery
    {
        return $this->hasMany(self::class, ['parent_id' => 'category_id']);
    }

    public function isRoot(): bool
    {
        return $this->parent_id === null || $this->parent_id === '';
    }

    /**
     * Build a nested tree from a flat array of Category models.
     * Returns [ ['item' => Category, 'children' => [...]], ... ]
     */
    public static function buildTree(array $items, ?string $parentId = null): array
    {
        $branch = [];
        foreach ($items as $item) {
            $p = ($item->parent_id === '' || $item->parent_id === null) ? null : $item->parent_id;
            if ($p === $parentId) {
                $branch[] = [
                    'item'     => $item,
                    'children' => self::buildTree($items, $item->category_id),
                ];
            }
        }
        return $branch;
    }

    /**
     * Flatten a tree into rows with a computed depth level.
     * Returns [ ['item' => Category, 'depth' => int], ... ]
     */
    public static function flattenTree(array $tree, int $depth = 0): array
    {
        $flat = [];
        foreach ($tree as $node) {
            $flat[] = ['item' => $node['item'], 'depth' => $depth];
            if (!empty($node['children'])) {
                foreach (self::flattenTree($node['children'], $depth + 1) as $child) {
                    $flat[] = $child;
                }
            }
        }
        return $flat;
    }

    /**
     * Collect all descendant category_ids of a given category_id.
     */
    public static function getDescendantIds(string $categoryId, array $allItems): array
    {
        $ids = [];
        foreach ($allItems as $item) {
            if ($item->parent_id === $categoryId) {
                $ids[] = $item->category_id;
                $ids = array_merge($ids, self::getDescendantIds($item->category_id, $allItems));
            }
        }
        return $ids;
    }
}
