<?php

declare(strict_types=1);

/**
 * Class SoundbiteModel Model for podcasts_soundbites table in database
 *
 * @copyright  2020 Ad Aures
 * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
 * @link       https://castopod.org/
 */

namespace Modules\PremiumPodcasts\Models;

use CodeIgniter\Model;
use Modules\PremiumPodcasts\Entities\Subscription;

class SubscriptionModel extends Model
{
    /**
     * @var string
     */
    protected $table = 'subscriptions';

    /**
     * @var string
     */
    protected $primaryKey = 'id';

    /**
     * @var string[]
     */
    protected $allowedFields = [
        'id',
        'podcast_id',
        'email',
        'token',
        'status',
        'status_message',
        'expires_at',
        'created_by',
        'updated_by',
    ];

    protected $returnType = Subscription::class;

    /**
     * @var bool
     */
    protected $useSoftDeletes = false;

    /**
     * @var bool
     */
    protected $useTimestamps = true;

    /**
     * @var string[]
     */
    protected $afterInsert = ['clearCache'];

    /**
     * @var string[]
     */
    protected $afterUpdate = ['clearCache'];

    /**
     * @var string[]
     */
    protected $beforeDelete = ['clearCache'];

    public function getSubscriptionById(int $subscriptionId): ?Subscription
    {
        $cacheName = "subscription#{$subscriptionId}";
        if (! ($found = cache($cacheName))) {
            $found = $this->find($subscriptionId);

            cache()
                ->save($cacheName, $found, DECADE);
        }

        return $found;
    }

    /**
     * @return Subscription[]
     */
    public function getPodcastSubscriptions(int $podcastId): array
    {
        $cacheName = "podcast#{$podcastId}_subscriptions";
        if (! ($found = cache($cacheName))) {
            $found = $this->where('podcast_id', $podcastId)
                ->findAll();

            cache()
                ->save($cacheName, $found, DECADE);
        }

        return $found;
    }

    /**
     * @param string $token plain-text token to be encrypted and matched against encrypted tokens in database
     */
    public function validateSubscription(int|string $podcastIdOrHandle, string $token): ?Subscription
    {
        $subscriptionModel = $this;

        if (is_int($podcastIdOrHandle)) {
            $this->where('id', $podcastIdOrHandle);
        } else {
            $this->select('subscriptions.*')
                ->where('handle', $podcastIdOrHandle)
                ->join('podcasts', 'podcasts.id = subscriptions.podcast_id');
        }

        return $subscriptionModel
            ->where([
                'token'      => hash('sha256', $token),
                'status'     => 'active',
                'expires_at' => null,
            ])
            ->orWhere('`expires_at` > UTC_TIMESTAMP()', null, false)
            ->first();
    }

    /**
     * @param mixed[] $data
     *
     * @return mixed[]
     */
    protected function clearCache(array $data): array
    {
        $subscription = (new self())->find(is_array($data['id']) ? $data['id'][0] : $data['id']);

        cache()
            ->delete("subscription#{$subscription->id}");
        cache()
            ->delete("podcast#{$subscription->podcast_id}_subscriptions");

        return $data;
    }
}