<?php

namespace Kylin\Licensing\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Kylin\Core\ApiResponse;
use Kylin\Licensing\Enums\LicensingErrorCode;
use Kylin\Licensing\Exceptions\LicenseExpiredException;
use Kylin\Licensing\Services\LicenseVerifier;
use Symfony\Component\HttpFoundation\Response;

/**
 * 许可证验证中间件
 */
class VerifyLicense
{
    public function __construct(
        private readonly LicenseVerifier $verifier,
    ) {}

    public function handle(Request $request, Closure $next, string $package = '*'): Response
    {
        // 本地开发环境跳过许可证验证
        if (app()->environment('local')) {
            return $next($request);
        }

        $licenseKey = config('kylin-licensing.key')
            ?? $request->header('X-License-Key');

        if (empty($licenseKey)) {
            return $this->handleError($request, LicensingErrorCode::LicenseNotFound, '许可证密钥缺失');
        }

        try {
            $this->verifier->assertValid();

            if ($package !== '*') {
                $this->verifier->assertPackageAuthorized($package);
            }

            $data = $this->verifier->getLicenseData();
            if ($data && ! $this->isDomainAllowed($data, $request->getHost())) {
                return $this->handleError($request, LicensingErrorCode::LicenseDomainMismatch, '当前域名不在许可证授权范围内');
            }

            if ($data && ! $this->isIpAllowed($data, $request->ip())) {
                return $this->handleError($request, LicensingErrorCode::LicenseIpMismatch, '当前IP不在许可证授权范围内');
            }
        } catch (LicenseExpiredException $e) {
            return $this->handleError($request, $e->errorCode, $e->getMessage());
        }

        return $next($request);
    }

    private function isDomainAllowed(array $data, string $domain): bool
    {
        $allowed = $data['domain'] ?? null;
        if (empty($allowed)) {
            return true;
        }
        if (str_starts_with($allowed, '*.')) {
            return str_ends_with($domain, substr($allowed, 1));
        }
        return $allowed === $domain;
    }

    private function isIpAllowed(array $data, string $ip): bool
    {
        $allowed = $data['ip'] ?? null;
        if (empty($allowed)) {
            return true;
        }
        return $allowed === $ip;
    }

    private function handleError(Request $request, LicensingErrorCode $errorCode, string $message): Response
    {
        if ($request->expectsJson() || $request->is('api/*') || $request->is('kylin/*')) {
            return ApiResponse::error(
                code: $errorCode->value(),
                message: $message,
                httpStatus: 403,
            );
        }

        if ($request->is('login') || $request->is('/')) {
            return response()->view('admin.license-warning', [
                'error' => $message,
                'error_code' => $errorCode->value(),
            ], 403);
        }

        return response()->view('admin.license-warning', [
            'error' => $message,
            'error_code' => $errorCode->value(),
        ], 403);
    }
}
