<?php

namespace App\Services;

use App\Models\Core\Setting;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

/**
 * Professional License Verification Service
 *
 * Multi-layer security approach:
 * - Domain fingerprinting
 * - Token-based verification
 * - Periodic background checks
 * - Response signature validation
 * - Distributed verification logic
 */
class LicenseService
{
    private const API_BASE = 'https://verifylicense.online/api/licence-verification';
    private const VERIFICATION_INTERVAL = 7; // days
    private const GRACE_PERIOD = 30; // days before blocking features

    /**
     * Verify purchase code during installation
     */
    public function verifyPurchase(string $purchaseCode, string $envatoUsername): array
    {
        try {
            $fingerprint = $this->generateDomainFingerprint();

            $params = [
                'domain' => $this->getDomain(),
                'software_id' => config('installer.software_id'),
                'version' => config('installer.version'),
                'purchase_key' => $purchaseCode,
                'envato_username' => $envatoUsername,
                'fingerprint' => $fingerprint,
                'timestamp' => time()
            ];

            // Add request signature for integrity
            $params['signature'] = $this->generateRequestSignature($params);

            Log::info('License verification request', [
                'domain' => $params['domain'],
                'username' => $envatoUsername,
                'fingerprint' => substr($fingerprint, 0, 10) . '...'
            ]);

            $response = Http::timeout(30)
                ->withHeaders(['Accept' => 'application/json'])
                ->post(self::API_BASE . '/verify-purchase', $params);

            if (!$response->successful()) {
                Log::error('License API error', [
                    'status' => $response->status(),
                    'body' => $response->body()
                ]);

                return [
                    'success' => false,
                    'message' => 'Unable to connect to license verification server. Please try again.'
                ];
            }

            $data = $response->json();

            // Validate response structure
            if (!$this->isValidResponse($data)) {
                Log::error('Invalid license response structure', ['data' => $data]);
                return [
                    'success' => false,
                    'message' => 'Invalid response from license server.'
                ];
            }

            // Validate response signature if provided
            if (isset($data['signature']) && !$this->verifyResponseSignature($data)) {
                Log::error('License response signature validation failed');
                return [
                    'success' => false,
                    'message' => 'License verification failed: Invalid signature.'
                ];
            }

            if ($data['success']) {
                // Store license data securely (may fail during installation if DB not ready)
                $this->storeLicenseData($purchaseCode, $envatoUsername, $data);

                Log::info('License verified successfully', [
                    'username' => $envatoUsername,
                    'domain' => $params['domain']
                ]);
            }

            return [
                'success' => $data['success'],
                'message' => $data['message'] ?? 'License verification completed.',
                'code' => $data['code'] ?? null
            ];

        } catch (\Exception $e) {
            Log::error('License verification exception', [
                'error' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine()
            ]);

            return [
                'success' => false,
                'message' => 'An error occurred during license verification: ' . $e->getMessage()
            ];
        }
    }

    /**
     * Periodic background verification (called by scheduled task)
     */
    public function periodicVerification(): bool
    {
        try {
            $lastVerified = $this->getLastVerificationDate();

            // Check if verification is due
            if ($lastVerified && $lastVerified->diffInDays(now()) < self::VERIFICATION_INTERVAL) {
                return true; // Still valid
            }

            $purchaseKey = $this->getLicenseKey();
            $username = $this->getLicenseUsername();

            if (!$purchaseKey || !$username) {
                Log::warning('License credentials not found for periodic verification');
                return false;
            }

            $params = [
                'domain' => $this->getDomain(),
                'software_id' => config('installer.software_id'),
                'version' => config('installer.version'),
                'purchase_key' => $purchaseKey,
                'envato_username' => $username,
                'fingerprint' => $this->generateDomainFingerprint(),
                'check_type' => 'periodic'
            ];

            $response = Http::timeout(20)->post(self::API_BASE . '/verify-purchase', $params);

            if ($response->successful()) {
                $data = $response->json();

                if (isset($data['success']) && $data['success']) {
                    $this->updateVerificationTimestamp();
                    Cache::put('license_status', 'valid', now()->addDays(self::VERIFICATION_INTERVAL));
                    return true;
                }
            }

            // Handle verification failure gracefully
            $this->handleVerificationFailure();
            return false;

        } catch (\Exception $e) {
            Log::error('Periodic verification failed', ['error' => $e->getMessage()]);
            // Don't block on network errors - graceful degradation
            return true;
        }
    }

    /**
     * Check if license is currently valid (used by middleware)
     */
    public function isLicenseValid(): bool
    {
        // Skip if app is not installed
        if (!env('APP_INSTALL', false)) {
            return true;
        }

        // Check cache first for performance
        $cachedStatus = Cache::get('license_status');
        if ($cachedStatus === 'valid') {
            return true;
        }

        try {
            // Check database verification state
            $lastVerified = $this->getLastVerificationDate();
            $gracePeriodEnd = $this->getGracePeriodEnd();

            if (!$lastVerified) {
                return false;
            }

            // Allow grace period for network issues
            if ($gracePeriodEnd && now()->lt($gracePeriodEnd)) {
                return true;
            }

            // Check if within acceptable verification window
            $daysSinceVerification = $lastVerified->diffInDays(now());

            if ($daysSinceVerification <= self::GRACE_PERIOD) {
                return true;
            }

            return false;
        } catch (\Exception $e) {
            Log::error('License validation error', ['error' => $e->getMessage()]);
            // If database is not available, allow access during installation
            return true;
        }
    }

    /**
     * Generate unique domain fingerprint
     */
    private function generateDomainFingerprint(): string
    {
        $domain = $this->getDomain();
        $serverSignature = php_uname('n') . PHP_VERSION;

        return hash('sha256', $domain . $serverSignature . config('app.key'));
    }

    /**
     * Generate request signature for integrity
     */
    private function generateRequestSignature(array $params): string
    {
        $signatureData = $params['domain'] .
                        $params['purchase_key'] .
                        $params['timestamp'] .
                        config('app.key');

        return hash_hmac('sha256', $signatureData, config('installer.software_id'));
    }

    /**
     * Verify response signature from API
     */
    private function verifyResponseSignature(array $response): bool
    {
        if (!isset($response['signature'])) {
            return true; // Optional signature
        }

        $expectedData = ($response['success'] ? 'true' : 'false') .
                       ($response['code'] ?? '') .
                       config('installer.software_id');

        $expectedSignature = hash_hmac('sha256', $expectedData, config('app.key'));

        return hash_equals($expectedSignature, $response['signature']);
    }

    /**
     * Validate API response structure
     */
    private function isValidResponse(array $data): bool
    {
        return isset($data['success'], $data['code'], $data['message']);
    }

    /**
     * Store license data securely in database
     */
    private function storeLicenseData(string $purchaseCode, string $username, array $apiResponse): void
    {
        // During installation, database tables may not exist yet
        // Check if app is installed before trying to save to database
        if (!env('APP_INSTALL', false)) {
            Log::info('Skipping license data storage - app not installed yet (will be saved after migration)');
            return;
        }

        try {
            $encryptedToken = $this->generateLicenseToken($purchaseCode, $username);

            // Get verification count safely
            $verificationCount = 1;
            try {
                $verificationCount = $this->getVerificationCount() + 1;
            } catch (\Exception $e) {
                Log::info('Could not get verification count, using default value of 1');
            }

            $settings = [
                'purchase_key' => $purchaseCode,
                'envato_username' => $username,
                'license_token' => $encryptedToken,
                'license_verified_at' => Carbon::now()->toDateTimeString(),
                'license_status' => 'active',
                'domain_fingerprint' => $this->generateDomainFingerprint(),
                'verification_count' => $verificationCount
            ];

            foreach ($settings as $key => $value) {
                Setting::updateOrCreate(
                    ['key' => $key],
                    ['value' => $value]
                );
            }

            Cache::put('license_status', 'valid', now()->addDays(self::VERIFICATION_INTERVAL));

            Log::info('License data stored successfully in database');
        } catch (\Exception $e) {
            // If settings table doesn't exist yet, just log
            Log::warning('Could not store license data in database', [
                'error' => $e->getMessage()
            ]);
        }
    }

    /**
     * Generate secure license token (not encryption, just hashing)
     */
    private function generateLicenseToken(string $purchaseCode, string $username): string
    {
        $data = $purchaseCode . $username . $this->getDomain() . config('app.key');
        return hash('sha384', $data);
    }

    /**
     * Update verification timestamp
     */
    private function updateVerificationTimestamp(): void
    {
        Setting::updateOrCreate(
            ['key' => 'license_verified_at'],
            ['value' => Carbon::now()->toDateTimeString()]
        );

        Setting::updateOrCreate(
            ['key' => 'verification_count'],
            ['value' => $this->getVerificationCount() + 1]
        );
    }

    /**
     * Handle verification failure gracefully
     */
    private function handleVerificationFailure(): void
    {
        $failureCount = (int) Setting::where('key', 'license_failure_count')->value('value') ?? 0;
        $failureCount++;

        Setting::updateOrCreate(
            ['key' => 'license_failure_count'],
            ['value' => $failureCount]
        );

        if ($failureCount === 1) {
            // Start grace period on first failure
            Setting::updateOrCreate(
                ['key' => 'license_grace_period_start'],
                ['value' => Carbon::now()->toDateTimeString()]
            );
        }

        // Update cache with warning status
        Cache::put('license_status', 'warning', now()->addDay());

        Log::warning('License verification failed', [
            'failure_count' => $failureCount,
            'grace_period_active' => $failureCount <= 3
        ]);
    }

    /**
     * Get domain without protocol
     */
    private function getDomain(): string
    {
        return parse_url(url('/'), PHP_URL_HOST) ?? 'localhost';
    }

    /**
     * Get last verification date
     */
    private function getLastVerificationDate(): ?Carbon
    {
        $timestamp = Setting::where('key', 'license_verified_at')->value('value');
        return $timestamp ? Carbon::parse($timestamp) : null;
    }

    /**
     * Get grace period end date
     */
    private function getGracePeriodEnd(): ?Carbon
    {
        $start = Setting::where('key', 'license_grace_period_start')->value('value');
        return $start ? Carbon::parse($start)->addDays(self::GRACE_PERIOD) : null;
    }

    /**
     * Get verification count
     */
    private function getVerificationCount(): int
    {
        return (int) Setting::where('key', 'verification_count')->value('value') ?? 0;
    }

    /**
     * Get stored license key
     */
    private function getLicenseKey(): ?string
    {
        return Setting::where('key', 'purchase_key')->value('value');
    }

    /**
     * Get stored license username
     */
    private function getLicenseUsername(): ?string
    {
        return Setting::where('key', 'envato_username')->value('value');
    }

    /**
     * Validate domain hasn't changed
     */
    public function validateDomainIntegrity(): bool
    {
        // Skip if app is not installed
        if (!env('APP_INSTALL', false)) {
            return true;
        }

        try {
            $storedFingerprint = Setting::where('key', 'domain_fingerprint')->value('value');

            if (!$storedFingerprint) {
                return false;
            }

            $currentFingerprint = $this->generateDomainFingerprint();

            if ($storedFingerprint !== $currentFingerprint) {
                Log::critical('Domain fingerprint mismatch detected', [
                    'stored' => substr($storedFingerprint, 0, 10) . '...',
                    'current' => substr($currentFingerprint, 0, 10) . '...'
                ]);
                return false;
            }

            return true;
        } catch (\Exception $e) {
            Log::error('Domain integrity check error', ['error' => $e->getMessage()]);
            return true;
        }
    }
}
