<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\License;
use App\Models\Product;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class LicenseController extends Controller
{
    public function index(): JsonResponse
    {
        return response()->json(['data' => License::query()->with(['product', 'clientAccount'])->latest()->paginate()]);
    }

    public function store(Request $request): JsonResponse
    {
        $payload = $request->validate([
            'key' => ['sometimes', 'string', 'max:80', 'unique:licenses,key'],
            'product_id' => ['required', 'uuid', 'exists:products,id'],
            'client_account_id' => ['required', 'uuid', 'exists:client_accounts,id'],
            'domains' => ['nullable', 'array'],
            'domains.*' => ['string', 'max:253'],
            'seats' => ['sometimes', 'integer', 'min:1'],
            'status' => ['sometimes', 'string', Rule::in(['active', 'inactive', 'suspended', 'expired'])],
            'expires_at' => ['nullable', 'date'],
            'metadata' => ['sometimes', 'array'],
        ]);

        $payload['domains'] = $this->normalizeDomains($payload['domains'] ?? []);
        $license = License::query()->create($payload);

        return response()->json(['data' => $license->load(['product', 'clientAccount'])], 201);
    }

    public function show(License $license): JsonResponse
    {
        return response()->json(['data' => $license->load(['product', 'clientAccount'])]);
    }

    public function update(Request $request, License $license): JsonResponse
    {
        $payload = $request->validate([
            'domains' => ['nullable', 'array'],
            'domains.*' => ['string', 'max:253'],
            'seats' => ['sometimes', 'integer', 'min:1'],
            'status' => ['sometimes', 'string', Rule::in(['active', 'inactive', 'suspended', 'expired'])],
            'expires_at' => ['nullable', 'date'],
            'metadata' => ['sometimes', 'array'],
        ]);

        if (array_key_exists('domains', $payload)) {
            $payload['domains'] = $this->normalizeDomains($payload['domains'] ?? []);
        }

        $license->update($payload);

        return response()->json(['data' => $license->refresh()->load(['product', 'clientAccount'])]);
    }

    public function verify(Request $request): JsonResponse
    {
        $payload = $request->validate([
            'license_key' => ['required', 'string'],
            'product_slug' => ['required', 'string'],
            'domain' => ['nullable', 'string', 'max:253'],
        ]);

        $product = Product::query()->where('slug', $payload['product_slug'])->first();
        $license = License::query()
            ->with('product')
            ->where('key', $payload['license_key'])
            ->first();

        $domain = isset($payload['domain']) ? strtolower(trim($payload['domain'])) : null;
        $domains = array_map(fn (string $value) => strtolower(trim($value)), $license?->domains ?? []);
        $domainAllowed = ! $domain || $domains === [] || in_array($domain, $domains, true);
        $valid = $product
            && $license
            && $license->product_id === $product->id
            && $license->status === 'active'
            && (! $license->expires_at || $license->expires_at->isFuture())
            && $domainAllowed;

        return response()->json([
            'data' => [
                'valid' => $valid,
                'reason' => $valid ? 'ok' : 'license_not_allowed',
                'license' => $license ? [
                    'key' => $license->key,
                    'status' => $license->status,
                    'expires_at' => $license->expires_at?->toIso8601String(),
                    'seats' => $license->seats,
                ] : null,
                'product' => $product ? [
                    'slug' => $product->slug,
                    'name' => $product->name,
                ] : null,
            ],
        ], $valid ? 200 : 403);
    }

    private function normalizeDomains(array $domains): array
    {
        return array_values(array_unique(array_map(fn (string $domain) => strtolower(trim($domain)), $domains)));
    }
}
