<?php

declare(strict_types=1);

namespace App\Domain\SmartLink\Services;

use App\Domain\SmartLink\Entities\LinkDestination;
use App\Domain\SmartLink\Entities\SmartLink;
use App\Domain\SmartLink\Repositories\GeoRoutingRuleRepository;
use App\Domain\SmartLink\Repositories\LinkDestinationRepository;
use App\Framework\Core\ValueObjects\CountryCode;
use App\Framework\Http\HttpRequest;
use App\Infrastructure\GeoIp\GeoIp;

final readonly class LinkRoutingEngine
{
    public function __construct(
        private LinkDestinationRepository $destinationRepository,
        private GeoRoutingRuleRepository $geoRoutingRuleRepository,
        private GeoIp $geoIp
    ) {
    }

    public function resolveDestination(
        SmartLink $smartLink,
        HttpRequest $request
    ): LinkDestination {
        // Check if link is accessible
        if (! $smartLink->canBeAccessed()) {
            throw new \DomainException('Link is not accessible');
        }

        // Check click limit
        if ($smartLink->settings->hasClickLimitReached($this->getCurrentClicks($smartLink))) {
            throw new \DomainException('Link has reached click limit');
        }

        // Apply routing strategies in order
        if ($smartLink->settings->enableGeoRouting) {
            $ip = $request->server->getClientIp();
            $country = $this->geoIp->getCountryCode($ip);
            $geoDestination = $this->applyGeoRouting($smartLink, $country);

            if ($geoDestination !== null) {
                return $geoDestination;
            }
        }

        // Fallback to default destination
        return $this->getDefaultDestination($smartLink);
    }

    private function applyGeoRouting(SmartLink $link, CountryCode $country): ?LinkDestination
    {
        // Find geo-routing rule for this link and country
        $geoRule = $this->geoRoutingRuleRepository->findByLinkAndCountry($link->id, $country);

        if ($geoRule === null) {
            return null;
        }

        // Find the destination referenced by the geo rule
        $destination = $this->destinationRepository->findById($geoRule->destinationId);

        return $destination;
    }

    private function getDefaultDestination(SmartLink $link): LinkDestination
    {
        $defaultDestination = $this->destinationRepository->findDefaultByLinkId($link->id);

        if ($defaultDestination !== null) {
            return $defaultDestination;
        }

        // Get first destination by priority
        $destinations = $this->destinationRepository->findByLinkId($link->id);

        if (empty($destinations)) {
            throw new \DomainException('No destinations configured for this link');
        }

        return $destinations[0];
    }

    private function getCurrentClicks(SmartLink $link): int
    {
        // TODO: Implement click counting
        return 0;
    }
}
