<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Distributed\Lease;

final class DistributedJobLease
{
    public function __construct(
        private readonly string $leaseId,
        private readonly string $jobId,
        private readonly string $nodeId,
        private readonly string $workerId,
        private readonly string $status = DistributedLeaseStatus::ACTIVE,
        private readonly string $leasedAt = '',
        private readonly string $expiresAt = '',
        private readonly int $renewCount = 0,
        private readonly string $releasedAt = ''
    ) {}

    public static function create(string $jobId, string $nodeId, string $workerId, int $ttlSeconds = 60): self
    {
        $leaseId = 'lease_' . substr(hash('sha256', $jobId . $nodeId . $workerId . microtime(true)), 0, 20);

        return new self(
            $leaseId,
            $jobId,
            $nodeId,
            $workerId,
            DistributedLeaseStatus::ACTIVE,
            date('c'),
            date('c', time() + max(1, $ttlSeconds)),
            0,
            ''
        );
    }

    public static function fromArray(array $data): self
    {
        return new self(
            (string) ($data['leaseId'] ?? ''),
            (string) ($data['jobId'] ?? ''),
            (string) ($data['nodeId'] ?? ''),
            (string) ($data['workerId'] ?? ''),
            (string) ($data['status'] ?? DistributedLeaseStatus::ACTIVE),
            (string) ($data['leasedAt'] ?? ''),
            (string) ($data['expiresAt'] ?? ''),
            (int) ($data['renewCount'] ?? 0),
            (string) ($data['releasedAt'] ?? '')
        );
    }

    public function leaseId(): string { return $this->leaseId; }
    public function jobId(): string { return $this->jobId; }
    public function nodeId(): string { return $this->nodeId; }
    public function workerId(): string { return $this->workerId; }
    public function status(): string { return $this->status; }

    public function active(): bool
    {
        return $this->status === DistributedLeaseStatus::ACTIVE && !$this->expired();
    }

    public function expired(): bool
    {
        return strtotime($this->expiresAt) <= time();
    }

    public function renew(int $ttlSeconds = 60): self
    {
        return new self(
            $this->leaseId,
            $this->jobId,
            $this->nodeId,
            $this->workerId,
            DistributedLeaseStatus::ACTIVE,
            $this->leasedAt,
            date('c', time() + max(1, $ttlSeconds)),
            $this->renewCount + 1,
            ''
        );
    }

    public function release(): self
    {
        return new self(
            $this->leaseId,
            $this->jobId,
            $this->nodeId,
            $this->workerId,
            DistributedLeaseStatus::RELEASED,
            $this->leasedAt,
            $this->expiresAt,
            $this->renewCount,
            date('c')
        );
    }

    public function markExpired(): self
    {
        return new self(
            $this->leaseId,
            $this->jobId,
            $this->nodeId,
            $this->workerId,
            DistributedLeaseStatus::EXPIRED,
            $this->leasedAt,
            $this->expiresAt,
            $this->renewCount,
            $this->releasedAt
        );
    }

    public function toArray(): array
    {
        return [
            'leaseId' => $this->leaseId,
            'jobId' => $this->jobId,
            'nodeId' => $this->nodeId,
            'workerId' => $this->workerId,
            'status' => $this->status,
            'active' => $this->active(),
            'expired' => $this->expired(),
            'leasedAt' => $this->leasedAt !== '' ? $this->leasedAt : date('c'),
            'expiresAt' => $this->expiresAt !== '' ? $this->expiresAt : date('c'),
            'renewCount' => $this->renewCount,
            'releasedAt' => $this->releasedAt,
        ];
    }
}
