<?php

class QtrExternalScanStatus implements JsonSerializable
{
    private string $uri = '';
    private string $state = '';
    private int $processed_files = 0;
    private int $popularity = 0;
    private int $priority = 0;
    private int $port = 0;
    private string $url = '';
    private string $title = '';
    private string $details = '';
    private int $age = 0;
    private int $download_mb = 0;
    private string $host = '';
    private int $rating = 0;
    private string $protocol = '';
    private string $country = '';
    private int $downloaded_mb = 0;
    private bool $blocked = false;
    private string $ipaddr = '';
    private string $is_blacklisted = '';

    /* =====================
     *  Getters / Setters
     * ===================== */

    public function getUri(): string { return $this->uri; }
    public function setUri(string $uri): self { $this->uri = $uri; return $this; }

    public function getState(): string { return $this->state; }
    public function setState(string $state): self { $this->state = $state; return $this; }

    public function getProcessedFiles(): int { return $this->processed_files; }
    public function setProcessedFiles(int $v): self { $this->processed_files = $v; return $this; }

    public function getPopularity(): int { return $this->popularity; }
    public function setPopularity(int $v): self { $this->popularity = $v; return $this; }

    public function getPriority(): int { return $this->priority; }
    public function setPriority(int $v): self { $this->priority = $v; return $this; }

    public function getPort(): int { return $this->port; }
    public function setPort(int $v): self { $this->port = $v; return $this; }

    public function getUrl(): string { return $this->url; }
    public function setUrl(string $url): self { $this->url = $url; return $this; }

    public function getTitle(): string { return $this->title; }
    public function setTitle(string $title): self { $this->title = $title; return $this; }

    public function getDetails(): string { return $this->details; }
    public function setDetails(string $details): self { $this->details = trim($details); return $this; }

    public function getAge(): int { return $this->age; }
    public function setAge(int $age): self { $this->age = $age; return $this; }

    public function getDownloadMb(): int { return $this->download_mb; }
    public function setDownloadMb(int $v): self { $this->download_mb = $v; return $this; }

    public function getHost(): string { return $this->host; }
    public function setHost(string $host): self { $this->host = $host; return $this; }

    public function getRating(): int { return $this->rating; }
    public function setRating(int $rating): self { $this->rating = $rating; return $this; }

    public function getProtocol(): string { return $this->protocol; }
    public function setProtocol(string $protocol): self { $this->protocol = $protocol; return $this; }

    public function getCountry(): string { return $this->country; }
    public function setCountry(string $country): self { $this->country = $country; return $this; }

    public function getDownloadedMb(): int { return $this->downloaded_mb; }
    public function setDownloadedMb(int $v): self { $this->downloaded_mb = $v; return $this; }

    public function isBlocked(): bool { return $this->blocked; }
    public function setBlocked(bool $blocked): self { $this->blocked = $blocked; return $this; }

    public function getIpaddr(): string { return $this->ipaddr; }
    public function setIpaddr(string $ip): self { $this->ipaddr = $ip; return $this; }

    /* --- is_blacklisted (string) --- */

    public function getIsBlacklisted(): string
    {
        return $this->is_blacklisted;
    }

    public function setIsBlacklisted(string $value): self
    {
        // Normalize input
        $value = strtoupper(trim($value));
        $this->is_blacklisted = ($value === 'YES') ? 'YES' : 'NO';
        return $this;
    }

    /* =====================
     *  Serialization
     * ===================== */

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }

    public function toArray(?string $fallback = null): array
    {
        $str = static function (string $value) use ($fallback): string {
            return ($fallback !== null && $value === '') ? $fallback : $value;
        };

        return [
            'uri'             => $str($this->uri),
            'state'           => $str($this->state),
            'processed_files' => $this->processed_files,
            'popularity'      => $this->popularity,
            'priority'        => $this->priority,
            'port'            => $this->port,
            'url'             => $str($this->url),
            'title'           => $str($this->title),
            'details'         => $str($this->details),
            'age'             => ($this->age > 0)? $this->age: 'Not performed',
            'download_mb'     => $this->download_mb,
            'host'            => $str($this->host),
            'rating'          => $this->rating,
            'protocol'        => $str($this->protocol),
            'country'         => $str($this->country),
            'downloaded_mb'   => $this->downloaded_mb,
            'blocked'         => (int)$this->blocked,
            'ipaddr'          => $str($this->ipaddr),
            'is_blacklisted'  => $str($this->is_blacklisted),
        ];
    }

    /* =====================
     *  Deserialization
     * ===================== */

    public static function fromArray(array $data): self
    {
        $obj = new self();

        $obj->setUri((string)($data['uri'] ?? ''));
        $obj->setState((string)($data['state'] ?? ''));
        $obj->setProcessedFiles((int)($data['processed_files'] ?? 0));
        $obj->setPopularity((int)($data['popularity'] ?? 0));
        $obj->setPriority((int)($data['priority'] ?? 0));
        $obj->setPort((int)($data['port'] ?? 0));
        $obj->setUrl((string)($data['url'] ?? ''));
        $obj->setTitle((string)($data['title'] ?? ''));
        $obj->setDetails((string)($data['details'] ?? ''));
        $obj->setAge((int)($data['age'] ?? 0));
        $obj->setDownloadMb((int)($data['download_mb'] ?? 0));
        $obj->setHost((string)($data['host'] ?? ''));
        $obj->setRating((int)($data['rating'] ?? 0));
        $obj->setProtocol((string)($data['protocol'] ?? ''));
        $obj->setCountry((string)($data['country'] ?? ''));
        $obj->setDownloadedMb((int)($data['downloaded_mb'] ?? 0));
        $obj->setBlocked((bool)($data['blocked'] ?? false));
        $obj->setIpaddr((string)($data['ipaddr'] ?? ''));

        // Optional string field, defaults to "NO"
        if (isset($data['is_blacklisted'])) {
            $obj->setIsBlacklisted((string)$data['is_blacklisted']);
        }

        return $obj;
    }

    public static function fromJson(string $json): self
    {
        //$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
        //$data = json_decode($json, true, 512);
        //return self::fromArray($data);

        try {
            $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);

            if (!is_array($data)) {
                return self::fromArray([]);
            }

            return self::fromArray($data);
        } catch (\Throwable $e) {
            // Any JSON error, malformed input, or unexpected value
            return self::fromArray([]);
        }
    }

    public function toJson(int $flags = JSON_UNESCAPED_SLASHES): string
    {
        return json_encode($this, $flags);
    }
}
