<?php

declare(strict_types=1);

namespace App\Framework\Auth\Attributes;

use App\Framework\Auth\ValueObjects\IpAuthPolicy;
use Attribute;

/**
 * Attribute für IP-basierte Authentifizierung
 */
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]
final readonly class IpAuth
{
    /**
     * @param array<int, string> $allowedIps Array von erlaubten IP-Adressen/Patterns/CIDR-Ranges
     * @param array<int, string> $deniedIps Array von verbotenen IP-Adressen/Patterns/CIDR-Ranges
     * @param bool $localOnly Nur lokale IP-Adressen erlauben
     * @param bool $adminOnly Nur localhost (127.0.0.1, ::1) erlauben
     * @param bool $denyPublic Öffentliche IP-Adressen explizit verbieten
     * @param string $policyName Name einer vordefinierten Policy
     */
    public function __construct(
        public array $allowedIps = [],
        public array $deniedIps = [],
        public bool $localOnly = false,
        public bool $adminOnly = false,
        public bool $denyPublic = false,
        public string $policyName = ''
    ) {
    }

    /**
     * Create IpAuthPolicy from this attribute
     */
    public function createPolicy(): IpAuthPolicy
    {
        // Use predefined policy if specified
        if (! empty($this->policyName)) {
            return match ($this->policyName) {
                'local-only' => IpAuthPolicy::localOnly(),
                'admin-only' => IpAuthPolicy::adminOnly(),
                'development' => IpAuthPolicy::development(),
                default => throw new \InvalidArgumentException("Unknown policy: {$this->policyName}")
            };
        }

        // Handle shortcuts
        if ($this->adminOnly) {
            return IpAuthPolicy::adminOnly();
        }

        if ($this->localOnly) {
            return IpAuthPolicy::localOnly();
        }

        // Create custom policy
        return IpAuthPolicy::fromConfig([
            'allowed' => $this->allowedIps,
            'denied' => $this->deniedIps,
            'deny_public' => $this->denyPublic,
        ]);
    }

    /**
     * Factory methods for common scenarios
     */
    public static function localOnly(): self
    {
        return new self(localOnly: true);
    }

    public static function adminOnly(): self
    {
        return new self(adminOnly: true);
    }

    /**
     * @param array<int, string> $ips
     */
    public static function allowIps(array $ips): self
    {
        return new self(allowedIps: $ips);
    }

    /**
     * @param array<int, string> $ips
     */
    public static function denyIps(array $ips): self
    {
        return new self(deniedIps: $ips);
    }

    public static function development(): self
    {
        return new self(policyName: 'development');
    }
}
