<?php

namespace Modules\AppManager\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Modules\AppManager\Entities\ManagedScript;
use Modules\AppManager\Entities\DownloadableFile;

class DownloadableFileController extends Controller
{
    protected string $storageDisk = 'local'; // Use 'local' for storage/app, or 'public' if files need web access (less secure for this use case)
    protected string $baseStoragePath = 'app_manager_files';

    /**
     * Display a listing of the resource.
     * @param ManagedScript $script
     * @return \Illuminate\Contracts\View\View
     */
    public function index(ManagedScript $script)
    {
        $files = $script->downloadableFiles()->orderBy('version', 'desc')->orderBy('file_name')->paginate(15);
        return view('appmanager::admin.downloadable_files.index', compact('script', 'files'));
    }

    /**
     * Show the form for creating a new resource.
     * @param ManagedScript $script
     * @return \Illuminate\Contracts\View\View
     */
    public function create(ManagedScript $script)
    {
        return view('appmanager::admin.downloadable_files.create', compact('script'));
    }

    /**
     * Store a newly created resource in storage.
     * @param Request $request
     * @param ManagedScript $script
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(Request $request, ManagedScript $script)
    {
        $request->validate([
            'uploaded_file' => 'required|file|max:102400', // Max 100MB, adjust as needed
            'version' => 'required|string|max:50',
            'target_path' => 'required|string|max:255',
            'description' => 'nullable|string',
            'is_critical' => 'boolean',
        ]);

        $data = $request->only(['version', 'target_path', 'description']);
        $data['is_critical'] = $request->has('is_critical');

        if ($request->hasFile('uploaded_file')) {
            $file = $request->file('uploaded_file');
            $originalFileName = $file->getClientOriginalName();
            // Sanitize original file name for storage path, or use a UUID
            $safeFileName = Str::slug(pathinfo($originalFileName, PATHINFO_FILENAME)) . '.' . $file->getClientOriginalExtension();

            $versionPath = Str::slug($data['version']);
            $securePath = "{$this->baseStoragePath}/{$script->slug}/{$versionPath}";

            // Store the file
            $storedFilePath = $file->storeAs($securePath, $safeFileName, $this->storageDisk);

            if (!$storedFilePath) {
                return redirect()->back()->with('error', 'Failed to upload file. Please check storage permissions.')->withInput();
            }

            $data['file_name'] = $originalFileName;
            $data['file_path'] = $storedFilePath; // Path relative to the disk's root
            $data['file_hash'] = hash_file('sha256', Storage::disk($this->storageDisk)->path($storedFilePath));
        } else {
            return redirect()->back()->with('error', 'File is required.')->withInput();
        }

        $script->downloadableFiles()->create($data);

        return redirect()->route('admin.appmanager.scripts.files.index', $script)
                         ->with('success', 'Downloadable file uploaded and created successfully.');
    }

    /**
     * Show the form for editing the specified resource.
     * @param ManagedScript $script
     * @param DownloadableFile $file
     * @return \Illuminate\Contracts\View\View
     */
    public function edit(ManagedScript $script, DownloadableFile $file)
    {
        if ($file->managed_script_id !== $script->id) {
            abort(404); // Or redirect with error
        }
        return view('appmanager::admin.downloadable_files.edit', compact('script', 'file'));
    }

    /**
     * Update the specified resource in storage.
     * @param Request $request
     * @param ManagedScript $script
     * @param DownloadableFile $file
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(Request $request, ManagedScript $script, DownloadableFile $file)
    {
        if ($file->managed_script_id !== $script->id) {
            abort(404);
        }

        $request->validate([
            'uploaded_file' => 'nullable|file|max:102400', // Optional on update
            'version' => 'required|string|max:50',
            'target_path' => 'required|string|max:255',
            'description' => 'nullable|string',
            'is_critical' => 'boolean',
        ]);

        $data = $request->only(['version', 'target_path', 'description']);
        $data['is_critical'] = $request->has('is_critical');

        if ($request->hasFile('uploaded_file')) {
            // Delete old file
            if ($file->file_path && Storage::disk($this->storageDisk)->exists($file->file_path)) {
                Storage::disk($this->storageDisk)->delete($file->file_path);
            }

            $newUploadedFile = $request->file('uploaded_file');
            $originalFileName = $newUploadedFile->getClientOriginalName();
            $safeFileName = Str::slug(pathinfo($originalFileName, PATHINFO_FILENAME)) . '.' . $newUploadedFile->getClientOriginalExtension();
            $versionPath = Str::slug($data['version']);
            $securePath = "{$this->baseStoragePath}/{$script->slug}/{$versionPath}";

            $storedFilePath = $newUploadedFile->storeAs($securePath, $safeFileName, $this->storageDisk);

            if (!$storedFilePath) {
                return redirect()->back()->with('error', 'Failed to upload new file. Please check storage permissions.')->withInput();
            }

            $data['file_name'] = $originalFileName;
            $data['file_path'] = $storedFilePath;
            $data['file_hash'] = hash_file('sha256', Storage::disk($this->storageDisk)->path($storedFilePath));
        }

        $file->update($data);

        return redirect()->route('admin.appmanager.scripts.files.index', $script)
                         ->with('success', 'Downloadable file updated successfully.');
    }

    /**
     * Remove the specified resource from storage.
     * @param ManagedScript $script
     * @param DownloadableFile $file
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy(ManagedScript $script, DownloadableFile $file)
    {
        if ($file->managed_script_id !== $script->id) {
            abort(404);
        }

        try {
            if ($file->file_path && Storage::disk($this->storageDisk)->exists($file->file_path)) {
                Storage::disk($this->storageDisk)->delete($file->file_path);
            }
            $file->delete();
            return redirect()->route('admin.appmanager.scripts.files.index', $script)
                             ->with('success', 'Downloadable file deleted successfully.');
        } catch (\Exception $e) {
            return redirect()->route('admin.appmanager.scripts.files.index', $script)
                             ->with('error', 'Failed to delete file: ' . $e->getMessage());
        }
    }
}