<?php

namespace App\Subscription\Service;

use App\Config\Repository\SiteConfigRepository;
use App\Payment\Entity\Payment;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Exception\AppException;
use App\Subscription\Entity\ClinicSubscription;
use App\Subscription\Repository\ClinicSubscriptionRepository;
use App\Subscription\Repository\SubscriptionPeriodRepository;
use App\Subscription\Repository\SubscriptionPlanRepository;

class SubscriptionService
{
    public function __construct(
        private readonly ClinicSubscriptionRepository $subscriptionRepo,
        private readonly SubscriptionPlanRepository   $planRepo,
        private readonly SubscriptionPeriodRepository $periodRepo,
        private readonly SiteConfigRepository         $configRepo,
    ) {}

    public function getActiveSubscription(string $entityType, int $entityId): ?ClinicSubscription
    {
        return $this->subscriptionRepo->findActive($entityType, $entityId);
    }

    public function hasFeature(string $entityType, int $entityId, string $feature): bool
    {
        $subscription = $this->getActiveSubscription($entityType, $entityId);
        if ($subscription === null) {
            return false;
        }

        return $subscription->getPlan()->hasFeature($feature);
    }

    public function getSecretaryLimit(string $entityType, int $entityId): int
    {
        $subscription = $this->getActiveSubscription($entityType, $entityId);
        if ($subscription === null) {
            return 1;
        }

        return $subscription->getPlan()->getMaxSecretaries();
    }

    public function hasUsedTrial(string $entityType, int $entityId): bool
    {
        return $this->subscriptionRepo->hasUsedTrial($entityType, $entityId);
    }

    public function activateTrial(string $entityType, int $entityId): ClinicSubscription
    {
        if ($this->hasUsedTrial($entityType, $entityId)) {
            throw new AppException(ErrorCodes::ERR_TRIAL_ALREADY_USED, null, 422);
        }

        $trialEnabled = $this->configRepo->get('trial_enabled');
        if ($trialEnabled === '0') {
            throw new AppException(ErrorCodes::ERR_TRIAL_DISABLED, null, 422);
        }

        $basicPlan = $this->planRepo->findByName('basic');
        if ($basicPlan === null) {
            throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, null, 500);
        }

        $trialPeriod = $this->periodRepo->findTrialPeriodForPlan($basicPlan);
        if ($trialPeriod === null) {
            throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, null, 500);
        }

        $expiresAt = $this->calculateExpiresAt(null, $trialPeriod->getDurationMonths());

        $subscription = new ClinicSubscription(
            $entityType,
            $entityId,
            $basicPlan,
            $trialPeriod,
            true,
            $expiresAt,
            null
        );

        $this->subscriptionRepo->save($subscription);

        return $subscription;
    }

    public function createFromPayment(Payment $payment, string $entityType, int $entityId, string $periodUuid): ClinicSubscription
    {
        $period = $this->periodRepo->findByUuid($periodUuid);
        if ($period === null) {
            throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, null, 404);
        }

        $currentSub = $this->getActiveSubscription($entityType, $entityId);
        $currentExpires = $currentSub?->getExpiresAt();

        $expiresAt = $this->calculateExpiresAt($currentExpires, $period->getDurationMonths());

        $subscription = new ClinicSubscription(
            $entityType,
            $entityId,
            $period->getPlan(),
            $period,
            false,
            $expiresAt,
            $payment
        );

        $this->subscriptionRepo->save($subscription);

        return $subscription;
    }

    public function calculateExpiresAt(?int $currentExpiresAt, int $durationMonths): int
    {
        $base = max($currentExpiresAt ?? 0, time());
        return $base + $durationMonths * 30 * 86400;
    }
}
