<?php

namespace App\Http\Controllers;

use App\Models\Application;
use App\Models\Category;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\File as HttpFile;
use Illuminate\Support\Str;

class AdminController extends Controller
{
    protected function isTempUploadPath(string $path): bool
    {
        $tempRoot = storage_path('app/temp_uploads');
        if (!is_dir($tempRoot) && !mkdir($tempRoot, 0755, true) && !is_dir($tempRoot)) {
            return false;
        }

        $realTempRoot = realpath($tempRoot);
        $realPath = realpath($path);

        if ($realTempRoot === false || $realPath === false) {
            return false;
        }

        return str_starts_with($realPath, $realTempRoot);
    }

    public function dashboard()
    {
        $totalApps = Application::count();
        $totalCategories = Category::count();
        $topApps = Application::orderByDesc('downloads')->limit(5)->get();

        return view('admin.dashboard', compact('totalApps', 'totalCategories', 'topApps'));
    }

    public function applications()
    {
        $applications = Application::with('category')->latest()->get();
        $categories = Category::all();
        return view('admin.applications.index', compact('applications', 'categories'));
    }

    public function createApplication()
    {
        $categories = Category::all();
        return view('admin.applications.create', compact('categories'));
    }

    public function storeApplication(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'description' => 'required|string',
            'category_id' => 'required|exists:categories,id',
            'platform' => 'required|in:Android,PC,iOS,macOS',
            'version' => 'required|string|max:50',
            'icon' => 'nullable|image|max:2048',
            'arch_files' => 'required|array|min:1',
            'arch_files.*.architecture' => 'required|string',
            'arch_files.*.file' => 'nullable|file|max:524288000',  // 500 MB
            'arch_files.*.temp_path' => 'nullable|string',
        ]);

        $validator->after(function ($validator) use ($request) {
            foreach ($request->input('arch_files', []) as $index => $fileData) {
                if (!$request->hasFile("arch_files.$index.file") && empty($fileData['temp_path'])) {
                    $validator->errors()->add("arch_files.$index.file", 'An application file is required.');
                }
            }
        });

        $data = $validator->validate();

        if ($request->hasFile('icon')) {
            $data['icon_path'] = $request->file('icon')->store('apps/icons', 'public');
        }

        $data['slug'] = Str::slug($data['name']) . '-' . time();
        $data['downloads'] = 0;
        $data['download_url'] = ''; // Legacy field

        $application = Application::create($data);

        foreach ($data['arch_files'] as $index => $fileData) {
            $architecture = $fileData['architecture'];
            $uploadedFile = $request->file("arch_files.$index.file");
            $path = null;
            $fileSize = 0;

            if ($uploadedFile) {
                $extension = $uploadedFile->getClientOriginalExtension();
                $filename = pathinfo($uploadedFile->getClientOriginalName(), PATHINFO_FILENAME) . '-' . time() . '.' . $extension;
                $path = $uploadedFile->storeAs('apps/files', $filename, 'public');
                $fileSize = $uploadedFile->getSize();
            } elseif (!empty($fileData['temp_path'])) {
                $tempPath = storage_path('app/' . ltrim($fileData['temp_path'], '/'));
                if (!file_exists($tempPath) || !$this->isTempUploadPath($tempPath)) {
                    return Redirect::back()->withErrors(['arch_files.' . $index . '.file' => 'Uploaded file could not be found or is invalid.'])->withInput();
                }

                $originalName = pathinfo($tempPath, PATHINFO_FILENAME);
                $extension = pathinfo($tempPath, PATHINFO_EXTENSION);
                $filename = $originalName . '-' . time() . '.' . $extension;
                $path = Storage::disk('public')->putFileAs('apps/files', new HttpFile($tempPath), $filename);
                $fileSize = filesize($tempPath);
                unlink($tempPath);
            }

            if (!$path) {
                continue;
            }

            $application->files()->create([
                'architecture' => $architecture,
                'file_path' => $path,
                'file_size' => $fileSize,
            ]);

            if ($index == 0) {
                $application->update(['download_url' => $path]);
            }
        }

        if ($request->expectsJson()) {
            return response()->json([
                'message' => 'Application uploaded successfully.',
                'redirect' => route('admin.applications.index'),
            ]);
        }

        return Redirect::route('admin.applications.index')->with('success', 'Application uploaded successfully.');
    }

    public function uploadChunk(Request $request)
    {
        $request->validate([
            'upload_id' => 'required|string',
            'file_index' => 'required|integer|min:0',
            'chunk_index' => 'required|integer|min:0',
            'chunk_count' => 'required|integer|min:1',
            'file_name' => 'required|string',
            'file_size' => 'required|integer|min:1',
            'chunk' => 'required|file|max:2560', // 2.5 MB (chunks are 1 MB; extra headroom for multipart)
        ]);

        $uploadId = preg_replace('/[^A-Za-z0-9_\-]/', '', $request->upload_id);
        $fileIndex = (int) $request->file_index;
        $chunkIndex = (int) $request->chunk_index;
        $chunkCount = (int) $request->chunk_count;
        $originalName = basename($request->file_name);
        $safeName = preg_replace('/[^A-Za-z0-9\.\-_]/', '_', $originalName);

        $tempDir = storage_path("app/temp_uploads/{$uploadId}");
        if (!is_dir($tempDir) && !mkdir($tempDir, 0755, true) && !is_dir($tempDir)) {
            return response()->json(['error' => 'Unable to create temporary upload directory.'], 500);
        }

        $targetPath = "{$tempDir}/{$fileIndex}_{$safeName}";
        $chunkFile = $request->file('chunk');
        $contents = file_get_contents($chunkFile->getPathname());

        if ($chunkIndex === 0 && file_exists($targetPath)) {
            unlink($targetPath);
        }

        file_put_contents($targetPath, $contents, $chunkIndex === 0 ? LOCK_EX : FILE_APPEND | LOCK_EX);
        unlink($chunkFile->getPathname());

        if ($chunkIndex === $chunkCount - 1) {
            if (filesize($targetPath) !== (int) $request->file_size) {
                return response()->json(['error' => 'Assembled chunk size mismatch.'], 422);
            }

            return response()->json([
                'temp_path' => 'temp_uploads/' . $uploadId . '/' . basename($targetPath),
                'complete' => true,
            ]);
        }

        return response()->json([
            'temp_path' => 'temp_uploads/' . $uploadId . '/' . basename($targetPath),
            'complete' => false,
        ]);
    }

    public function editApplication($id)
    {
        $application = Application::with('files')->findOrFail($id);
        $categories = Category::all();
        return view('admin.applications.edit', [
            'app_model' => $application,
            'categories' => $categories
        ]);
    }

    public function updateApplication(Request $request, $id)
    {
        $application = Application::findOrFail($id);
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'description' => 'required|string',
            'category_id' => 'required|exists:categories,id',
            'platform' => 'required|in:Android,PC,iOS,macOS',
            'version' => 'required|string|max:50',
            'icon' => 'nullable|image|max:2048',
            'arch_files' => 'nullable|array',
            'arch_files.*.id' => 'nullable|exists:application_files,id',
            'arch_files.*.architecture' => 'required|string',
            'arch_files.*.file' => 'nullable|file|max:524288000',  // 500 MB
            'arch_files.*.temp_path' => 'nullable|string',
        ]);

        $validator->after(function ($validator) use ($request) {
            foreach ($request->input('arch_files', []) as $index => $fileInput) {
                $hasFile = $request->hasFile("arch_files.$index.file");
                $hasTemp = !empty($fileInput['temp_path'] ?? null);
                $hasId = !empty($fileInput['id'] ?? null);

                if (!$hasId && !$hasFile && !$hasTemp) {
                    $validator->errors()->add("arch_files.$index.file", 'A file is required for each new architecture entry.');
                }
            }
        });

        $data = $validator->validate();
        $archFiles = $data['arch_files'] ?? [];
        unset($data['arch_files']);

        if ($request->hasFile('icon')) {
            $application->icon_path && Storage::disk('public')->delete($application->icon_path);
            $data['icon_path'] = $request->file('icon')->store('apps/icons', 'public');
        }

        if ($request->has('name')) {
            $data['slug'] = Str::slug($request->name) . '-' . time();
        }

        $application->update($data);

        if (!empty($archFiles)) {
            foreach ($archFiles as $index => $fileInput) {
                $architecture = $fileInput['architecture'];
                $fileId = $fileInput['id'] ?? null;
                $tempPath = $fileInput['temp_path'] ?? null;

                $archFile = $fileId ? $application->files()->find($fileId) : null;

                $fileData = [
                    'architecture' => $architecture,
                ];

                if ($request->hasFile("arch_files.$index.file") || $tempPath) {
                    if ($archFile) {
                        Storage::disk('public')->delete($archFile->file_path);
                    }

                    if ($request->hasFile("arch_files.$index.file")) {
                        $uploadedFile = $request->file("arch_files.$index.file");
                        $extension = $uploadedFile->getClientOriginalExtension();
                        $filename = pathinfo($uploadedFile->getClientOriginalName(), PATHINFO_FILENAME) . '-' . time() . '.' . $extension;
                        $path = $uploadedFile->storeAs('apps/files', $filename, 'public');
                        $fileSize = $uploadedFile->getSize();
                    } else {
                        $uploadedTempPath = storage_path('app/' . ltrim($tempPath, '/'));
                        if (!file_exists($uploadedTempPath) || !$this->isTempUploadPath($uploadedTempPath)) {
                            return Redirect::back()->withErrors(['arch_files.' . $index . '.file' => 'Uploaded file could not be found or is invalid.'])->withInput();
                        }

                        $originalName = pathinfo($uploadedTempPath, PATHINFO_FILENAME);
                        $extension = pathinfo($uploadedTempPath, PATHINFO_EXTENSION);
                        $filename = $originalName . '-' . time() . '.' . $extension;
                        $path = Storage::disk('public')->putFileAs('apps/files', new HttpFile($uploadedTempPath), $filename);
                        $fileSize = filesize($uploadedTempPath);
                        unlink($uploadedTempPath);
                    }

                    $fileData['file_path'] = $path;
                    $fileData['file_size'] = $fileSize;

                    if ($index == 0) {
                        $application->update(['download_url' => $fileData['file_path']]);
                    }
                }

                if ($archFile) {
                    $archFile->update($fileData);
                } else {
                    $application->files()->create($fileData);
                }
            }
        }

        if ($request->expectsJson()) {
            return response()->json([
                'message' => 'Application updated successfully.',
                'redirect' => route('admin.applications.index'),
            ]);
        }

        return Redirect::route('admin.applications.index')->with('success', 'Application updated successfully.');
    }

    public function destroyApplication($id)
    {
        $application = Application::findOrFail($id);

        // Delete Icon
        if ($application->icon_path) {
            Storage::disk('public')->delete(ltrim($application->icon_path, '/'));
        }

        // Delete all Architecture Files
        foreach ($application->files as $file) {
            Storage::disk('public')->delete(ltrim($file->file_path, '/'));
        }

        // Delete Legacy File
        if ($application->download_url) {
            Storage::disk('public')->delete(ltrim($application->download_url, '/'));
        }

        $application->delete();

        return Redirect::route('admin.applications.index')->with('success', 'Application removed successfully.');
    }

    public function categories()
    {
        $categories = Category::latest()->get();
        return view('admin.categories.index', compact('categories'));
    }

    public function storeCategory(Request $request)
    {
        $request->validate(['name' => 'required|string|max:100']);

        Category::create([
            'name' => $request->name,
            'slug' => Str::slug($request->name),
        ]);

        return Redirect::route('admin.categories.index')->with('success', 'Category created successfully.');
    }

    public function destroyCategory(Category $category)
    {
        $category->applications()->delete();
        $category->delete();

        return Redirect::route('admin.categories.index')->with('success', 'Category deleted successfully.');
    }
}
