<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Crypt;

/**
 * Self-hosted yazılım lisansı kaydı (PRC-59).
 *
 * State: `issued` boolean + `revoked_at` + `expires_at` (lifetime ürünlerde
 * expires_at null kalır, asla expire olmaz). `license_key` Crypt-encrypted.
 */
class ClientSoftwareLicense extends Model
{
    public const TYPE_LIFETIME = 'lifetime';
    public const TYPE_SUBSCRIPTION = 'subscription';

    protected $fillable = [
        'client_product_id',
        'client_id',
        'product_label',
        'module',
        'issued',
        'issued_at',
        'expires_at',
        'revoked_at',
        'license_type',
        'license_key',
        'host_binding',
        'binding_input',
        'module_data',
        'last_error',
        'last_attempt_at',
    ];

    protected $casts = [
        'host_binding' => 'array',
        'binding_input' => 'array',
        'module_data' => 'array',
        'issued' => 'boolean',
        'issued_at' => 'datetime',
        'expires_at' => 'datetime',
        'revoked_at' => 'datetime',
        'last_attempt_at' => 'datetime',
    ];

    protected $hidden = ['license_key'];

    /**
     * PRC-868 — license_key şifreli saklandığı için düz metinle sorgulanamaz.
     * Sorgulanabilir sha256 hash'i her kayıtta senkron tut (lisans doğrulama
     * endpoint'i buradan lookup yapar).
     */
    protected static function booted(): void
    {
        static::saving(function (self $license): void {
            $plain = $license->license_key; // accessor ile çözülmüş düz metin
            $license->license_key_hash = $plain ? hash('sha256', (string) $plain) : null;
        });
    }

    public function clientProduct(): BelongsTo
    {
        return $this->belongsTo(ClientProduct::class);
    }

    public function client(): BelongsTo
    {
        return $this->belongsTo(Client::class);
    }

    public function isActive(): bool
    {
        if (! $this->issued || $this->revoked_at !== null) {
            return false;
        }
        if ($this->license_type === self::TYPE_LIFETIME) {
            return true;
        }

        return $this->expires_at === null || $this->expires_at->isFuture();
    }

    public function isLifetime(): bool
    {
        return $this->license_type === self::TYPE_LIFETIME;
    }

    public function isRevoked(): bool
    {
        return $this->revoked_at !== null;
    }

    public function isExpired(): bool
    {
        return ! $this->isLifetime()
            && $this->expires_at !== null
            && $this->expires_at->isPast();
    }

    public function daysUntilExpiry(): ?int
    {
        if (! $this->expires_at) {
            return null;
        }

        return (int) round($this->expires_at->diffInDays(now(), false) * -1);
    }

    public function scopeIssued($q)
    {
        return $q->where('issued', true);
    }

    public function scopePendingIssue($q)
    {
        return $q->where('issued', false)->whereNull('revoked_at');
    }

    /**
     * Encrypt-on-set / decrypt-on-get for `license_key`.
     */
    protected function licenseKey(): Attribute
    {
        return Attribute::make(
            get: fn ($value) => $value === null ? null : $this->safeDecrypt($value),
            set: fn ($value) => $value === null ? null : Crypt::encryptString($value),
        );
    }

    private function safeDecrypt(string $value): string
    {
        try {
            return Crypt::decryptString($value);
        } catch (\Throwable $e) {
            return $value;
        }
    }
}
