<?php

namespace Modules\AppManager\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Http; // For Envato API call
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Modules\AppManager\Entities\License;
use Modules\AppManager\Entities\ManagedScript;
use Modules\AppManager\Entities\ActivationLog;
use Modules\AppManager\Entities\DownloadToken; // Import DownloadToken
use Illuminate\Http\JsonResponse;

class ActivationController extends Controller
{
    public function activate(Request $request): JsonResponse
    {
        Log::debug('AppManager Activation Request Data:', $request->all());
        Log::debug('AppManager Activation Request Content:', ['content' => $request->getContent()]); // Log raw content
        Log::debug('AppManager Activation Request Headers:', $request->headers->all());

        $validator = Validator::make($request->all(), [
            'license_key' => 'required_without:purchase_code|string|max:255',
            'purchase_code' => 'required_without:license_key|string|max:255',
            'product_slug' => 'required|string|exists:am_managed_scripts,slug',
            'domain' => 'required|string|max:255', // Consider validating as URL/domain
            'server_signature' => 'nullable|string|max:255', // Optional hash of server info
        ]);

        if ($validator->fails()) {
            return response()->json(['status' => 'error', 'message' => 'Validation failed.', 'errors' => $validator->errors()], 400);
        }

        $product = ManagedScript::where('slug', $request->input('product_slug'))->firstOrFail();
        $license = null;
        $envatoToken = config('appmanager.envato_personal_token');
        $purchaseCode = trim($request->input('purchase_code')); // Trim whitespace

        if ($request->filled('license_key')) {
            $license = License::where('license_key', $request->input('license_key'))
                              ->where('managed_script_id', $product->id)
                              ->first();
        } elseif ($request->filled('purchase_code') && $purchaseCode) {
            // Validate purchase code format before sending to Envato
            if (!preg_match("/^([a-f0-9]{8})-(([a-f0-9]{4})-){3}([a-f0-9]{12})$/i", $purchaseCode)) {
                $errorMsg = "Invalid purchase code format.";
                Log::info('AppManager: Invalid purchase code format received.', ['code' => $purchaseCode, 'product_slug' => $product->slug, 'ip' => $request->ip()]);
                $this->logActivationAttempt($request, $product, null, 'failed_invalid_purchase_code_format', $errorMsg);
                return response()->json(['status' => 'error', 'message' => $errorMsg], 400); // 400 for bad request
            }

            if ($product->envato_item_id && $envatoToken) {
                try {
                    $envatoResponse = Http::withToken($envatoToken)
                        ->withUserAgent(config('app.name', 'Laravel') . ' - AppManager Purchase Verification')
                        ->timeout(15) // Set a reasonable timeout
                        ->get("https://api.envato.com/v3/market/author/sale?code={$purchaseCode}");

                    if ($envatoResponse->successful()) {
                        $saleData = $envatoResponse->json();
                        if (isset($saleData['item']['id']) && $saleData['item']['id'] == $product->envato_item_id) {
                            // Purchase code is valid for this item
                            $baseLicenseData = [
                                'type' => 'codecanyon',
                                'customer_email' => $saleData['buyer'] ?? null,
                                'customer_name' => $saleData['buyer_username'] ?? ($saleData['buyer'] ?? null),
                                'status' => 'active', // Default to active on successful verification
                                'supported_until' => isset($saleData['supported_until']) ? \Carbon\Carbon::parse($saleData['supported_until']) : null,
                            ];

                            // Find existing license by purchase code for this product, or create a new one
                            $license = License::updateOrCreate(
                                ['purchase_code' => $purchaseCode, 'managed_script_id' => $product->id],
                                $baseLicenseData // These are values for creation or fields to be updated if found
                            );

                            // Ensure metadata is correctly updated/set.
                            // updateOrCreate handles the other fields from $baseLicenseData.
                            $newMetadata = $license->metadata ?? [];
                            $newMetadata['envato_license_type'] = $saleData['license'] ?? null;
                            $license->metadata = $newMetadata;

                            // Save if metadata changed or if updateOrCreate made changes not yet persisted
                            // (though updateOrCreate typically persists immediately). A single save here is robust.
                            $license->save();
                        } else {
                            // Valid response from Envato, but item ID doesn't match
                            $errorMsg = 'Purchase code is valid but for a different product.';
                            Log::warning('AppManager: Envato purchase code product mismatch.', ['code' => $purchaseCode, 'product_slug' => $product->slug, 'expected_item_id' => $product->envato_item_id, 'received_item_id' => $saleData['item']['id'] ?? 'N/A', 'ip' => $request->ip()]);
                            $this->logActivationAttempt($request, $product, null, 'failed_envato_product_mismatch', $errorMsg);
                            return response()->json(['status' => 'error', 'message' => $errorMsg], 403);
                        }
                    } else { // Envato request was not successful
                        $statusCode = $envatoResponse->status();
                        $envatoErrorBody = $envatoResponse->json() ?? ['description' => $envatoResponse->body()];
                        $errorDescription = $envatoErrorBody['description'] ?? 'Unknown Envato API error.';

                        if ($statusCode === 404) {
                            $errorMsg = 'Invalid purchase code or it does not belong to your items.';
                        } elseif ($statusCode === 403) {
                            $errorMsg = 'Envato API permission issue or token invalid. Please check your Envato token.';
                        } elseif ($statusCode === 401) {
                            $errorMsg = 'Envato API authentication failed. Please check your authorization header.';
                        } else {
                            $errorMsg = "Envato API error ({$statusCode}): {$errorDescription}";
                        }

                        Log::warning('AppManager: Envato API request failed.', ['code' => $purchaseCode, 'product_slug' => $product->slug, 'status_code' => $statusCode, 'response_body' => $envatoErrorBody, 'ip' => $request->ip()]);
                        $this->logActivationAttempt($request, $product, null, "failed_envato_api_s{$statusCode}", $errorMsg);
                        return response()->json(['status' => 'error', 'message' => $errorMsg], $statusCode >= 500 ? 503 : 403);
                    }
                } catch (\Illuminate\Http\Client\ConnectionException $e) {
                    Log::error('AppManager: Envato API connection error.', ['error' => $e->getMessage(), 'ip' => $request->ip()]);
                    $this->logActivationAttempt($request, $product, null, 'failed_envato_api_connection', 'Could not connect to verification server.');
                    return response()->json(['status' => 'error', 'message' => 'Could not connect to verification server. Please try again later.'], 503);
                }
            } else {
                 // Fallback to checking existing licenses if Envato details are not configured for the product
                 $license = License::where('purchase_code', $purchaseCode)
                                   ->where('managed_script_id', $product->id)
                                   ->first();
            }
        }

        if (!$license) {
            $this->logActivationAttempt($request, $product, null, 'failed_license_not_found', 'License key or purchase code not found or invalid for this product.');
            return response()->json(['status' => 'error', 'message' => 'License key or purchase code not found or invalid for this product.'], 403);
        }

        // Check license status
        if (!in_array($license->status, ['pending', 'active'])) {
            $this->logActivationAttempt($request, $product, $license, 'failed_license_status_inactive', 'License is not active (Status: '.$license->status.').');
            return response()->json(['status' => 'error', 'message' => 'License is not active. Current status: ' . $license->status], 403);
        }

        // Check expiry
        if ($license->expires_at && $license->expires_at->isPast()) {
            $this->logActivationAttempt($request, $product, $license, 'failed_license_expired', 'License has expired.');
            return response()->json(['status' => 'error', 'message' => 'License has expired.'], 403);
        }

        // Check activation limit (0 means unlimited)
        $domainToActivate = strtolower($request->input('domain'));
        $existingActivationsForDomain = $license->activationLogs()->where('activated_domain', $domainToActivate)->where('status', 'success')->exists(); // Ensure this uses the correct relationship name

        if (!$existingActivationsForDomain && $license->activation_limit > 0 && $license->current_activations >= $license->activation_limit) {
            $this->logActivationAttempt($request, $product, $license, 'failed_activation_limit_reached', 'Activation limit reached for this license.');
            return response()->json(['status' => 'error', 'message' => 'Activation limit reached for this license.'], 403);
        }

        // Log successful activation
        $activationLog = $this->logActivationAttempt($request, $product, $license, 'success', 'Activation successful.');

        if (!$existingActivationsForDomain) {
            $license->increment('current_activations');
        }
        if ($license->status === 'pending') {
            $license->status = 'active';
        }
        $license->save();

        // Generate a DownloadToken
        $downloadToken = DownloadToken::create([
            'license_id' => $license->id,
            // 'activation_log_id' => $activationLog->id, // Optional: If you add this FK to DownloadToken
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'expires_at' => now()->addMinutes(config('appmanager.download_token_ttl_minutes', 30)),
            'max_uses' => config('appmanager.download_token_max_uses', 5), // Allow a few uses for a set of files
        ]);
        $activationToken = $downloadToken->token;


        return response()->json([
            'status' => 'success',
            'message' => 'Application activated successfully.',
            'activation_token' => $activationToken, // For subsequent file downloads
            'product_info' => [
                'name' => $product->name,
                'version' => $product->current_version,
            ],
            'license_info' => [
                'status' => $license->status, 'expires_at' => $license->expires_at ? $license->expires_at->toIso8601String() : null,
                'supported_until' => $license->supported_until ? $license->supported_until->toIso8601String() : null,
                'type' => $license->type,
                'envato_license_type' => $license->metadata['envato_license_type'] ?? null
            ]
        ]);
    }

    public function validateLicense(Request $request): JsonResponse
    {
        // Similar validation as activate, but doesn't increment activation count
        // Just checks if the license is still valid for the given domain/product
        $validator = Validator::make($request->all(), [
            'license_key' => 'required|string|max:255',
            'product_slug' => 'required|string|exists:am_managed_scripts,slug',
            'domain' => 'required|string|max:255',
        ]);

        if ($validator->fails()) {
            return response()->json(['status' => 'error', 'message' => 'Validation failed.', 'errors' => $validator->errors()], 400);
        }

        $product = ManagedScript::where('slug', $request->input('product_slug'))->firstOrFail();
        $license = License::where('license_key', $request->input('license_key'))
                          ->where('managed_script_id', $product->id)
                          ->first();

        if (!$license || $license->status !== 'active' || ($license->expires_at && $license->expires_at->isPast())) {
            return response()->json(['status' => 'invalid', 'message' => 'License is invalid or expired.'], 403);
        }

        // Optionally, check if this domain is among the activated ones for this license
        $isActiveForDomain = $license->activationLogs()
                                    ->where('activated_domain', strtolower($request->input('domain')))
                                    ->where('status', 'success')
                                    ->exists();

        if (!$isActiveForDomain) {
             return response()->json(['status' => 'invalid', 'message' => 'License not activated for this domain.'], 403);
        }

        return response()->json(['status' => 'valid', 'message' => 'License is active.']);
    }

    private function logActivationAttempt(Request $request, ManagedScript $product, ?License $license, string $status, string $message): ActivationLog
    {
        return ActivationLog::create([
            'license_id' => $license?->id,
            'managed_script_id' => $product->id, // Always log the product context
            'license_key_attempt' => $request->input('license_key'),
            'purchase_code_attempt' => trim($request->input('purchase_code')), // Log trimmed code
            'activated_domain' => strtolower($request->input('domain')),
            'ip_address' => $request->ip(),
            'server_signature' => $request->input('server_signature'),
            'status' => $status,
            'message' => $message,
            'activated_at' => now(), // This will be handled by am_activation_logs table definition if it has `useCurrent`
        ]);
    }
}
