<?php

namespace objects;

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

class selfserve_config_versions_o extends db
{
    use db_object_t;

    public object_property $department_id;
    public object_property $status;
    public object_property $version_number;
    public object_property $config_json;
    public object_property $validation_result_json;
    public object_property $source_version_id;
    public object_property $created_by;
    public object_property $published_at;
    public object_property $created_at;
    public object_property $updated_at;
    public object_property $deleted_at;

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

    public function getObjectProperties(): void
    {
        $this->department_id = new object_property($this->table, $this->id, 'department_id', 'int', false);
        $this->status = new object_property($this->table, $this->id, 'status', 'string', false);
        $this->version_number = new object_property($this->table, $this->id, 'version_number', 'int', false);
        $this->config_json = new object_property($this->table, $this->id, 'config_json', 'json', false);
        $this->validation_result_json = new object_property($this->table, $this->id, 'validation_result_json', 'json', false);
        $this->source_version_id = new object_property($this->table, $this->id, 'source_version_id', 'int', false);
        $this->created_by = new object_property($this->table, $this->id, 'created_by', 'int', false);
        $this->published_at = new object_property($this->table, $this->id, 'published_at', 'datetime', false);
        $this->created_at = new object_property($this->table, $this->id, 'created_at', 'timestamp', false);
        $this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'timestamp', false);
        $this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false);
    }

    public function objectChanged(): void
    {
        // No-op for now.
    }

    public function add(
        int $departmentId,
        string $status,
        int $versionNumber,
        array $config,
        ?array $validationResult = null,
        ?int $sourceVersionId = null,
        ?int $createdBy = null,
        ?string $publishedAt = null,
    ): self {
        $configJson = json_encode($config, JSON_UNESCAPED_UNICODE);
        if ($configJson === false) {
            throw new \RuntimeException('Failed to encode self-serve config JSON: ' . json_last_error_msg());
        }

        $validationJson = null;
        if ($validationResult !== null) {
            $validationJson = json_encode($validationResult, JSON_UNESCAPED_UNICODE);
            if ($validationJson === false) {
                throw new \RuntimeException('Failed to encode self-serve validation JSON: ' . json_last_error_msg());
            }
        }

        $this->id = $this->add_object([
            'department_id' => $departmentId,
            'status' => $status,
            'version_number' => $versionNumber,
            // Pass JSON as escaped strings to avoid SQL quoting issues inside generic add_object().
            'config_json' => $configJson,
            'validation_result_json' => $validationJson,
            'source_version_id' => $sourceVersionId,
            'created_by' => $createdBy,
            'published_at' => $publishedAt,
        ]);
        $this->getObjectProperties();
        $this->objectChanged();
        return $this;
    }

    public function selectLatestByDepartmentAndStatus(int $departmentId, string $status): self
    {
        $rows = $this->getFieldsWhere([
            'department_id' => $departmentId,
            'status' => $status,
            'deleted_at' => null,
        ], ['id']);
        if ($rows === []) {
            return $this;
        }

        usort($rows, static fn(array $a, array $b): int => (int)$b['id'] <=> (int)$a['id']);
        $this->select((int)$rows[0]['id']);
        return $this;
    }

    public function listByDepartment(int $departmentId): array
    {
        $rows = $this->getFieldsWhere([
            'department_id' => $departmentId,
            'deleted_at' => null,
        ], ['id']);
        if ($rows === []) {
            return [];
        }

        usort($rows, static fn(array $a, array $b): int => (int)$b['id'] <=> (int)$a['id']);
        return array_map(function (array $row): array {
            return (new selfserve_config_versions_o())->select((int)$row['id'])->asArray();
        }, $rows);
    }

    public function asArray(): array
    {
        return [
            'id' => (int)$this->id,
            'department_id' => (int)$this->department_id->value(),
            'status' => (string)$this->status->value(),
            'version_number' => (int)$this->version_number->value(),
            'config' => (array)($this->config_json->value() ?? []),
            'validation_result' => (array)($this->validation_result_json->value() ?? []),
            'source_version_id' => $this->source_version_id->value() === null ? null : (int)$this->source_version_id->value(),
            'created_by' => $this->created_by->value() === null ? null : (int)$this->created_by->value(),
            'published_at' => $this->published_at->value() === null ? null : (string)$this->published_at->value(),
            'created_at' => (string)$this->created_at->value(),
            'updated_at' => $this->updated_at->value() === null ? null : (string)$this->updated_at->value(),
        ];
    }
}
