<?php

namespace App\Http\Controllers;

use App\Helpers\ProfileAuthorizationHelper;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use ZipArchive;

class BackupChunkUploadController extends Controller
{
    /**
     * Receive a single chunk of the backup file.
     * POST /posts/backup-upload/chunk
     */
    public function uploadChunk(Request $request): JsonResponse
    {
        $this->authorizeAdminAccess();

        $request->validate([
            'uploadId' => 'required|string|uuid',
            'chunkIndex' => 'required|integer|min:0|max:999',
            'totalChunks' => 'required|integer|min:1|max:1000',
            'chunk' => 'required|file|max:3072', // 3MB max per chunk
        ]);

        $uploadId = $request->input('uploadId');
        $chunkIndex = (int) $request->input('chunkIndex');
        $totalChunks = (int) $request->input('totalChunks');

        if ($chunkIndex >= $totalChunks) {
            return response()->json(['error' => 'Invalid chunk index'], 422);
        }

        $chunkDir = storage_path("app/temp/chunks/{$uploadId}");
        if (!File::isDirectory($chunkDir)) {
            File::makeDirectory($chunkDir, 0755, true);
        }

        $request->file('chunk')->move($chunkDir, "chunk_{$chunkIndex}");

        return response()->json([
            'success' => true,
            'chunkIndex' => $chunkIndex,
            'received' => count(File::files($chunkDir)),
            'total' => $totalChunks,
        ]);
    }

    /**
     * Finalize: reassemble chunks into the complete file.
     * POST /posts/backup-upload/finalize
     */
    public function finalize(Request $request): JsonResponse
    {
        $this->authorizeAdminAccess();

        $request->validate([
            'uploadId' => 'required|string|uuid',
            'totalChunks' => 'required|integer|min:1|max:1000',
            'fileName' => 'required|string|max:255',
        ]);

        $uploadId = $request->input('uploadId');
        $totalChunks = (int) $request->input('totalChunks');
        $fileName = basename($request->input('fileName'));

        $chunkDir = storage_path("app/temp/chunks/{$uploadId}");
        $outputDir = storage_path('app/temp');

        if (!File::isDirectory($outputDir)) {
            File::makeDirectory($outputDir, 0755, true);
        }

        // Verify all chunks exist
        for ($i = 0; $i < $totalChunks; $i++) {
            if (!File::exists("{$chunkDir}/chunk_{$i}")) {
                return response()->json(['error' => "Missing chunk {$i}"], 422);
            }
        }

        // Reassemble
        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        if (!in_array($ext, ['zip', 'json'])) {
            File::deleteDirectory($chunkDir);
            return response()->json(['error' => 'Invalid file type'], 422);
        }

        $assembledName = 'restore_' . uniqid() . '.' . $ext;
        $assembledPath = "{$outputDir}/{$assembledName}";

        $output = fopen($assembledPath, 'wb');
        for ($i = 0; $i < $totalChunks; $i++) {
            $chunkPath = "{$chunkDir}/chunk_{$i}";
            $input = fopen($chunkPath, 'rb');
            stream_copy_to_stream($input, $output);
            fclose($input);
        }
        fclose($output);

        // Clean up chunks
        File::deleteDirectory($chunkDir);

        // Validate ZIP if applicable
        if ($ext === 'zip') {
            $zip = new ZipArchive();
            if ($zip->open($assembledPath) !== true) {
                @unlink($assembledPath);
                return response()->json(['error' => 'Invalid ZIP file'], 422);
            }
            if ($zip->getFromName('backup.json') === false) {
                $zip->close();
                @unlink($assembledPath);
                return response()->json(['error' => 'ZIP does not contain backup.json'], 422);
            }
            $zip->close();
        }

        // Store path in session for Livewire to retrieve
        session(["backup_restore_file_{$uploadId}" => $assembledPath]);

        return response()->json([
            'success' => true,
            'uploadId' => $uploadId,
        ]);
    }

    /**
     * Authorization check matching RequiresAdminAuthorization trait logic.
     */
    private function authorizeAdminAccess(): void
    {
        $activeProfileType = session('activeProfileType');
        $activeProfileId = session('activeProfileId');

        if (!$activeProfileType || !$activeProfileId) {
            abort(403, 'No active profile selected');
        }

        $profile = $activeProfileType::find($activeProfileId);
        if (!$profile) {
            abort(403, 'Active profile not found');
        }

        ProfileAuthorizationHelper::authorize($profile);

        if ($profile instanceof \App\Models\Admin) {
            return;
        }
        if ($profile instanceof \App\Models\Bank && $profile->level === 0) {
            return;
        }

        abort(403, 'Admin or central bank access required');
    }
}
