<?php

namespace Modules\AppManager\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log;
use Modules\AppManager\Entities\ManagedScript;
use Modules\AppManager\Entities\DownloadableFile;
use Modules\AppManager\Entities\DownloadToken; // Import DownloadToken

class FileDownloadController extends Controller
{
    protected string $storageDisk;
    protected string $baseStoragePath = 'app_manager_files'; // Base path within the disk

    public function __construct()
    {
        $this->storageDisk = config('appmanager.storage_disk', 'local');
    }

    public function download(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'product_slug' => 'required|string|exists:am_managed_scripts,slug',
            'file_identifier' => 'required|string', // This could be the target_path or a unique ID/file_name
            'version' => 'required|string',
            'activation_token' => 'required|string', // The token received from successful activation
            'license_key' => 'sometimes|required|string', // Optional: For an extra layer of validation if token is tied to license
            'domain' => 'sometimes|required|string',      // Optional: If token is tied to a domain
        ]);

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

        // --- Robust Token Validation ---
        $downloadToken = DownloadToken::where('token', $request->input('activation_token'))->first();

        if (!$downloadToken) {
            Log::warning('AppManager: Invalid download token used.', ['token' => $request->input('activation_token'), 'ip' => $request->ip()]);
            return response()->json(['status' => 'error', 'message' => 'Invalid or expired download token.'], 403);
        }

        if ($downloadToken->isExpired()) {
            Log::info('AppManager: Expired download token used.', ['token_id' => $downloadToken->id, 'ip' => $request->ip()]);
            return response()->json(['status' => 'error', 'message' => 'Download token has expired.'], 403);
        }

        if ($downloadToken->isMaxUsesReached()) {
            Log::info('AppManager: Download token max uses reached.', ['token_id' => $downloadToken->id, 'ip' => $request->ip()]);
            return response()->json(['status' => 'error', 'message' => 'Download token usage limit reached.'], 403);
        }

        // Optional: Further checks if token is tied to specific license_key or domain
        // This requires the DownloadToken to have a direct relationship or stored metadata
        // For example, if DownloadToken belongs to a License:
        if ($request->filled('license_key') && $downloadToken->license->license_key !== $request->input('license_key')) {
             Log::warning('AppManager: Download token license mismatch.', [
                'token_id' => $downloadToken->id,
                'expected_key' => $downloadToken->license->license_key,
                'provided_key' => $request->input('license_key'),
                'ip' => $request->ip()
            ]);
            return response()->json(['status' => 'error', 'message' => 'Token not valid for this license.'], 403);
        }
        // You might also check if the token was generated for the correct product_slug via $downloadToken->license->managed_script_id

        // --- End Robust Token Validation ---


        $script = ManagedScript::where('slug', $request->input('product_slug'))->firstOrFail();
        $downloadableFile = DownloadableFile::where('managed_script_id', $script->id)
                                            ->where(function($query) use ($request) {
                                                // Allow lookup by target_path primarily, or file_name as a fallback
                                                $query->where('target_path', $request->input('file_identifier'))
                                                      ->orWhere('file_name', $request->input('file_identifier'));
                                            })
                                            ->where('version', $request->input('version'))
                                            ->first();

        if (!$downloadableFile) {
            Log::info('AppManager: Downloadable file not found or version mismatch.', $request->all());
            return response()->json(['status' => 'error', 'message' => 'File not found or version mismatch.'], 404);
        }

        $filePathOnDisk = $downloadableFile->file_path; // This path is relative to the disk's root

        if (!Storage::disk($this->storageDisk)->exists($filePathOnDisk)) {
            Log::error("AppManager: File source not found on server for download.", ['path' => $filePathOnDisk, 'request' => $request->all()]);
            return response()->json(['status' => 'error', 'message' => 'File source not found on server.'], 500);
        }

        // Optional: Verify hash before sending
        $currentHash = hash_file('sha256', Storage::disk($this->storageDisk)->path($filePathOnDisk));
        if ($downloadableFile->file_hash && $currentHash !== $downloadableFile->file_hash) {
            Log::critical("AppManager: CRITICAL - File hash mismatch for download.", [
                'file_record_id' => $downloadableFile->id,
                'path' => $filePathOnDisk,
                'stored_hash' => $downloadableFile->file_hash,
                'current_hash' => $currentHash
            ]);
            return response()->json(['status' => 'error', 'message' => 'File integrity check failed on server.'], 500);
        }
        
        $downloadToken->incrementUsage();
        // Optionally, delete the token if it has reached max uses and you want it to be strictly single-session for a set of downloads
        // if ($downloadToken->isMaxUsesReached()) { $downloadToken->delete(); }

        return Storage::disk($this->storageDisk)->download($filePathOnDisk, $downloadableFile->file_name, [
            'Content-Type' => Storage::disk($this->storageDisk)->mimeType($filePathOnDisk) ?? 'application/octet-stream',
            'X-File-Hash' => $downloadableFile->file_hash // Send hash for client-side verification
        ]);
    }
}
