<?php

declare(strict_types=1);

namespace App\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'installation')]
class Installation
{
    #[ORM\Id]
    #[ORM\Column(type: Types::INTEGER)]
    private int $id = 1;

    #[ORM\Column(type: Types::STRING, length: 64, nullable: true)]
    private ?string $licenseKey = null;

    #[ORM\Column(type: Types::STRING, length: 255)]
    private string $domain = '';

    #[ORM\Column(type: Types::STRING, length: 20, options: ['default' => 'starter'])]
    private string $plan = 'starter';

    /** demo, active, expired, invalid */
    #[ORM\Column(type: Types::STRING, length: 20, options: ['default' => 'demo'])]
    private string $licenseStatus = 'demo';

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $licenseExpiresAt = null;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $licenseCachedAt = null;

    #[ORM\Column(type: Types::TEXT, nullable: true)]
    private ?string $licenseCacheJson = null;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
    private \DateTimeImmutable $installedAt;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $demoExpiresAt = null;

    #[ORM\Column(type: Types::STRING, length: 20, options: ['default' => '1.0.0'])]
    private string $currentVersion = '1.0.0';

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
    private ?\DateTimeImmutable $lastUpdateCheck = null;

    #[ORM\Column(type: Types::TEXT, nullable: true)]
    private ?string $availableUpdateJson = null;

    public function __construct()
    {
        $this->installedAt = new \DateTimeImmutable();
        $this->demoExpiresAt = new \DateTimeImmutable('+7 days');
    }

    public function getId(): int { return $this->id; }

    public function getLicenseKey(): ?string { return $this->licenseKey; }
    public function setLicenseKey(?string $key): self { $this->licenseKey = $key; return $this; }

    public function getDomain(): string { return $this->domain; }
    public function setDomain(string $domain): self { $this->domain = $domain; return $this; }

    public function getPlan(): string { return $this->plan; }
    public function setPlan(string $plan): self { $this->plan = $plan; return $this; }

    public function getLicenseStatus(): string { return $this->licenseStatus; }
    public function setLicenseStatus(string $status): self { $this->licenseStatus = $status; return $this; }

    public function getLicenseExpiresAt(): ?\DateTimeImmutable { return $this->licenseExpiresAt; }
    public function setLicenseExpiresAt(?\DateTimeImmutable $dt): self { $this->licenseExpiresAt = $dt; return $this; }

    public function getLicenseCachedAt(): ?\DateTimeImmutable { return $this->licenseCachedAt; }
    public function setLicenseCachedAt(?\DateTimeImmutable $dt): self { $this->licenseCachedAt = $dt; return $this; }

    public function getLicenseCacheJson(): ?string { return $this->licenseCacheJson; }
    public function setLicenseCacheJson(?string $json): self { $this->licenseCacheJson = $json; return $this; }

    public function getInstalledAt(): \DateTimeImmutable { return $this->installedAt; }
    public function setInstalledAt(\DateTimeImmutable $dt): self { $this->installedAt = $dt; return $this; }

    public function getDemoExpiresAt(): ?\DateTimeImmutable { return $this->demoExpiresAt; }
    public function setDemoExpiresAt(?\DateTimeImmutable $dt): self { $this->demoExpiresAt = $dt; return $this; }

    public function isDemo(): bool
    {
        return $this->licenseKey === null || $this->licenseStatus === 'demo';
    }

    public function isDemoExpired(): bool
    {
        if (!$this->isDemo()) return false;
        if ($this->demoExpiresAt === null) return false;
        return $this->demoExpiresAt < new \DateTimeImmutable();
    }

    public function isLicenseValid(): bool
    {
        return $this->licenseStatus === 'active';
    }

    public function isExpired(): bool
    {
        return $this->licenseStatus === 'expired';
    }

    public function getDaysUntilExpiry(): ?int
    {
        if ($this->licenseExpiresAt === null) return null;
        $diff = (new \DateTimeImmutable())->diff($this->licenseExpiresAt);
        return $diff->invert ? -$diff->days : $diff->days;
    }

    public function getCachedLimits(): array
    {
        $data = $this->getDecodedCache();
        return $data['limits'] ?? ['maxUsers' => 3, 'maxNews' => 500, 'maxStorageMb' => 1024];
    }

    public function getCachedModules(): array
    {
        $data = $this->getDecodedCache();
        return $data['modules'] ?? ['menu', 'comment', 'seo'];
    }

    public function getCachedFeatures(): array
    {
        $data = $this->getDecodedCache();
        return $data['features'] ?? [];
    }

    public function getCurrentVersion(): string { return $this->currentVersion; }
    public function setCurrentVersion(string $v): self { $this->currentVersion = $v; return $this; }

    public function getLastUpdateCheck(): ?\DateTimeImmutable { return $this->lastUpdateCheck; }
    public function setLastUpdateCheck(?\DateTimeImmutable $dt): self { $this->lastUpdateCheck = $dt; return $this; }

    public function getAvailableUpdateJson(): ?string { return $this->availableUpdateJson; }
    public function setAvailableUpdateJson(?string $json): self { $this->availableUpdateJson = $json; return $this; }

    public function getAvailableUpdate(): ?array
    {
        if (!$this->availableUpdateJson) return null;
        $data = json_decode($this->availableUpdateJson, true);
        return ($data['update_available'] ?? false) ? $data : null;
    }

    public function shouldCheckUpdate(): bool
    {
        if ($this->lastUpdateCheck === null) return true;
        return $this->lastUpdateCheck < new \DateTimeImmutable('-6 hours');
    }

    public function shouldVerify(): bool
    {
        if ($this->licenseCachedAt === null) return true;
        $sixHoursAgo = new \DateTimeImmutable('-6 hours');
        return $this->licenseCachedAt < $sixHoursAgo;
    }

    private function getDecodedCache(): array
    {
        if (!$this->licenseCacheJson) return [];
        return json_decode($this->licenseCacheJson, true) ?: [];
    }
}
