<?php

namespace App\Services;

use App\Models\Product;
use App\Models\ProductFile;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;

class ProductFileService
{
    /**
     * Upload and encrypt a file for a product
     */
    public function uploadFile(Product $product, UploadedFile $file, string $description = null): ProductFile
    {
        // Validate file
        $this->validateFile($file);

        // Generate unique encryption key for this file
        $encryptionKey = Str::random(32);
        
        // Generate unique filename
        $originalName = $file->getClientOriginalName();
        $extension = $file->getClientOriginalExtension();
        $encryptedName = Str::uuid() . '.' . $extension;
        
        // Create directory path
        $directory = 'product-files/' . $product->id;
        $filePath = $directory . '/' . $encryptedName;

        // Read file content
        $fileContent = file_get_contents($file->getRealPath());
        
        // Calculate checksum
        $checksum = hash('sha256', $fileContent);
        
        // Encrypt file content
        $encryptedContent = $this->encryptContent($fileContent, $encryptionKey);
        
        // Store encrypted file
        Storage::disk('private')->put($filePath, $encryptedContent);
        
        // Encrypt the encryption key for storage
        $encryptedKey = Crypt::encryptString($encryptionKey);

        // Create database record
        $productFile = ProductFile::create([
            'product_id' => $product->id,
            'original_name' => $originalName,
            'encrypted_name' => $encryptedName,
            'file_path' => $filePath,
            'file_type' => $file->getMimeType(),
            'file_size' => $file->getSize(),
            'encryption_key' => $encryptedKey,
            'checksum' => $checksum,
            'description' => $description,
        ]);

        Log::info('Product file uploaded', [
            'product_id' => $product->id,
            'file_id' => $productFile->id,
            'original_name' => $originalName,
            'file_size' => $file->getSize()
        ]);

        return $productFile;
    }

    /**
     * Download a file for a user (with license and invoice verification)
     */
    public function downloadFile(ProductFile $file, $userId = null): ?array
    {
        // Verify user has license and paid invoice for this product
        if ($userId) {
            $permissions = $this->userCanDownloadFiles($file->product, $userId);
            if (!$permissions['can_download']) {
                return null;
            }
        }

        // Check if file exists
        if (!$file->fileExists()) {
            Log::error('File not found for download', ['file_id' => $file->id]);
            return null;
        }

        // Get decrypted content
        $content = $file->getDecryptedContent();
        if (!$content) {
            Log::error('Failed to decrypt file', ['file_id' => $file->id]);
            return null;
        }

        // Verify checksum
        if (hash('sha256', $content) !== $file->checksum) {
            Log::error('File checksum mismatch', ['file_id' => $file->id]);
            return null;
        }

        // Increment download count
        $file->incrementDownloadCount();

        Log::info('File downloaded', [
            'file_id' => $file->id,
            'user_id' => $userId,
            'download_count' => $file->download_count
        ]);

        return [
            'content' => $content,
            'filename' => $file->original_name,
            'mime_type' => $file->file_type,
            'size' => $file->file_size
        ];
    }

    /**
     * Delete a product file
     */
    public function deleteFile(ProductFile $file): bool
    {
        try {
            // Delete physical file
            if ($file->fileExists()) {
                Storage::disk('private')->delete($file->file_path);
            }

            // Delete database record
            $file->delete();

            Log::info('Product file deleted', [
                'file_id' => $file->id,
                'product_id' => $file->product_id
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('Failed to delete product file', [
                'file_id' => $file->id,
                'error' => $e->getMessage()
            ]);
            return false;
        }
    }

    /**
     * Get files for a product
     */
    public function getProductFiles(Product $product, bool $activeOnly = true): \Illuminate\Database\Eloquent\Collection
    {
        $query = $product->files();
        
        if ($activeOnly) {
            $query->where('is_active', true);
        }

        return $query->orderBy('created_at', 'desc')->get();
    }

    /**
     * Validate uploaded file
     */
    private function validateFile(UploadedFile $file): void
    {
        // Check file size (max 100MB)
        if ($file->getSize() > 100 * 1024 * 1024) {
            throw new \Exception('File size cannot exceed 100MB');
        }

        // Check file type
        $allowedTypes = [
            'application/zip',
            'application/x-zip-compressed',
            'application/x-rar-compressed',
            'application/pdf',
            'text/plain',
            'application/json',
            'application/xml',
            'text/xml',
            'application/javascript',
            'text/css',
            'text/html',
            'application/php',
            'application/x-php',
            'text/php',
            'application/sql',
            'text/sql',
            'image/jpeg',
            'image/png',
            'image/gif',
            'image/svg+xml',
        ];

        if (!in_array($file->getMimeType(), $allowedTypes)) {
            throw new \Exception('File type not allowed');
        }

        // Check for malicious content
        $this->scanFileForMaliciousContent($file);
    }

    /**
     * Scan file for malicious content
     */
    private function scanFileForMaliciousContent(UploadedFile $file): void
    {
        $content = file_get_contents($file->getRealPath());
        
        // Check for common malicious patterns
        $maliciousPatterns = [
            '/eval\s*\(/i',
            '/base64_decode\s*\(/i',
            '/exec\s*\(/i',
            '/system\s*\(/i',
            '/shell_exec\s*\(/i',
            '/passthru\s*\(/i',
            '/file_get_contents\s*\(\s*["\']http/i',
            '/curl_exec\s*\(/i',
            '/fopen\s*\(\s*["\']http/i',
        ];

        foreach ($maliciousPatterns as $pattern) {
            if (preg_match($pattern, $content)) {
                throw new \Exception('File contains potentially malicious content');
            }
        }
    }

    /**
     * Encrypt file content
     */
    private function encryptContent(string $content, string $key): string
    {
        $iv = substr(hash('sha256', $key), 0, 16);
        return openssl_encrypt($content, 'AES-256-CBC', $key, 0, $iv);
    }

    /**
     * Check if user has active license for product
     */
    private function userHasLicense(Product $product, $userId): bool
    {
        return $product->licenses()
            ->where('user_id', $userId)
            ->where('status', 'active')
            ->where(function ($q) {
                $q->whereNull('license_expires_at')
                  ->orWhere('license_expires_at', '>', now());
            })
            ->exists();
    }

    /**
     * Check if user has paid invoice for product
     */
    private function userHasPaidInvoice(Product $product, $userId): bool
    {
        return \App\Models\Invoice::where('product_id', $product->id)
            ->where('user_id', $userId)
            ->where('status', 'paid')
            ->exists();
    }

    /**
     * Check if user can download files (has license AND paid invoice)
     */
    public function userCanDownloadFiles(Product $product, $userId): array
    {
        $hasLicense = $this->userHasLicense($product, $userId);
        $hasPaidInvoice = $this->userHasPaidInvoice($product, $userId);
        
        return [
            'can_download' => $hasLicense && $hasPaidInvoice,
            'has_license' => $hasLicense,
            'has_paid_invoice' => $hasPaidInvoice,
            'message' => $this->getDownloadPermissionMessage($hasLicense, $hasPaidInvoice)
        ];
    }

    /**
     * Get appropriate message based on download permissions
     */
    private function getDownloadPermissionMessage(bool $hasLicense, bool $hasPaidInvoice): string
    {
        if (!$hasLicense && !$hasPaidInvoice) {
            return trans('app.You must purchase the product and pay the invoice first');
        } elseif (!$hasLicense) {
            return trans('app.You must purchase the product first');
        } elseif (!$hasPaidInvoice) {
            return trans('app.You must pay the invoice first');
        }
        
        return '';
    }
}
