<?php

namespace App\Http\Controllers\Frontend;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use App\Helpers\SeoHelper;
use App\Models\Upload;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Contracts\Encryption\DecryptException;
use App\Helpers\AnalyticsHelper;
use App\Models\FileReports;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Storage;

class FileController extends Controller
{
    public function file(
        Request $request,
        string $fileKey
    ): View {
        $filekeyArr = explode('.', $fileKey);
        $fileByKey = Upload::where('short_key', $filekeyArr[0])->first();
        $fileByName = Upload::where('filename', $fileKey)->first();

        if (!$fileByKey && !$fileByName) {
            abort(404);
        }

        $fileData = $fileByKey ?: $fileByName;

        $fName = $fileData->filename;
        $fType = $fileData->type;
        $fKey = $fileData->short_key;
        
        $fileName = $fileByKey
            ? "{$fKey}.{$fType}"
            : $fName;

        $check = isset($fileData->password) && $fileData->password
            ? (
                (Auth::check() && $fileData->created_by_id == Auth::id()) 
                    ? true 
                    : $this->checkPermission($fKey)) 
            : true;

        $fileExist = Storage::disk($fileData->disk)
            ->exists($fName);

        $rand = rand();
        $fileUrl = $fileExist 
            ? (
                $fileByKey
                    ? url("/get/{$fKey}.{$fType}?v={$rand}")
                    : url("/get/{$fName}?v={$rand}")
            )
            : url("/assets/image/file-deleted.webp");

        if (
            $fileExist 
            && $check 
            && affiliateSetting('status') == 1 
            && affiliateSetting('type') == 1
        ) {
            AnalyticsHelper::makeAffiliate(
                $fileData->id, 
                $request->ip()
            );
        }

        AnalyticsHelper::makeAnalytics(
            $fileData->id, 
            $request->ip()
        );
        $analyticsGet = AnalyticsHelper::getAnalytics(
            $fileData->id
        );

        if (!$fileExist) {
            $fileData->filetype = 'webp';
        }

        $seo = SeoHelper::pageSeo('file', $fileData);

        return view('frontend.file.index', [
            'functions' => 'frontend.file.function',
            'pageKey' => 'file',
            'seoData' => $seo,
            'permission' => $check,
            'file' => $fileData,
            'fileName' => $fileName,
            'fileUrl' => $fileUrl,
            'downloadUrl' => $fileUrl,
            'analytics' => $analyticsGet ?? false,
            'randomClass' => $this->randomKey(),
            'randomFunction' => $this->randomKey(),
            'playerFunction' => $this->randomKey(),
        ]);
    }

    public function file_get(
        string $fileKey = KBm71L6J1Ojg0n6hH1VxnRQ3VwpINyGlWHcr85Jq.jpg
    ): mixed {
        $filekeyArr = explode('.', $fileKey);
        $fileByKey = Upload::where('short_key', $filekeyArr[0])->first();
        $fileByName = Upload::where('filename', $fileKey)->first();

        $fileData = $fileByKey ?: $fileByName;
        $check = isset($fileData->password) && $fileData->password
            ? (
                (Auth::check() && $fileData->created_by_id == Auth::id()) 
                    ? true 
                    : $this->checkPermission($fileData->short_key)) 
            : true;
        if (!$check) {
            return response()
                ->file(public_path("assets/image/password-protected.webp"));
        }

        if ($fileByKey) {
            $rand = rand();
            $filename = "{$fileByKey->short_key}.{$fileByKey->filetype}?v={$rand}";
            return Storage::disk($fileByKey->disk)->exists($fileByKey->filename)
                ? Storage::disk($fileByKey->disk)
                    ->response($fileByKey->filename,$filename)
                : response()
                    ->file(public_path("assets/image/file-deleted.webp"));
        }

        if ($fileByName) {
            $rand = rand();
            return Storage::disk($fileByName->disk)->exists($fileByName->filename)
                ? Storage::disk($fileByName->disk)
                    ->response($fileByName->filename)
                : response()
                    ->file(public_path("assets/image/file-deleted.webp"));
        }

        return response()
            ->file(public_path("assets/image/file-deleted.webp"));
    }

    public function file_password(
        Request $request, 
        string $fileKey
    ): RedirectResponse {
        $request->validate([
            'file-password' => 'required|min:3|max:15',
        ]);

        $file = Upload::where("short_key", $fileKey)
            ->first();

        if (!$file) {
            return back()->withErrors([
                'error' => __('lang.file_not_found'),
            ]);
        }

        if ($file->password != $request->input('file-password')) {
            return back()->withErrors([
                'error' => __('lang.password_incorrect'),
            ]);
        }

        $fileKey = Crypt::encryptString($fileKey);
        $request->session()->push('files', $fileKey);

        return back();
    }

    public function file_download(
        string $fileKey
    ): mixed {
        $filekeyArr = explode('.', $fileKey);
        $fileByKey = Upload::where('short_key', $filekeyArr[0])->first();
        $fileByName = Upload::where('filename', $fileKey)->first();

        if (!$fileByKey && !$fileByName) {
            abort(404);
        }

        $fileData = $fileByKey ?: $fileByName;

        if (!$fileData) {
            return response()->json([
                'result' => false,
                'errors' => __('lang.file_not_found'),
            ]);
        }

        if (Storage::disk($fileData->disk)->exists($fileData->filename)) {

            if (
                affiliateSetting('status') == 1 
                && affiliateSetting('type') == 2
            ) {
                AnalyticsHelper::makeAffiliate(
                    $fileData->id, 
                    request()->ip()
                );
            }

            $filename = $fileByKey 
                ? "{$fileData->short_key}.{$fileData->filetype}" 
                : $fileData->filename;

            return Storage::disk($fileData->disk)
                ->download($fileData->filename, $filename);
        }

        return response()->json([
            'result' => false,
            'errors' => __('lang.file_not_found'),
        ]);
    }

    public function clear(
        Request $request
    ): void {
        $request->session()->forget('files');
    }

    public function report(
        Request $request,
        string $fileKey
    ): JsonResponse {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'reason' => 'required|string|max:10000',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'result' => false,
                'errors' => $validator->errors(),
            ]);
        }

        $filekeyArr = explode('.', $fileKey);
        $fileByKey = Upload::where('short_key', $filekeyArr[0])->first();
        $fileByName = Upload::where('filename', $fileKey)->first();

        if (!$fileByKey && !$fileByName) {
            abort(404);
        }

        $fileData = $fileByKey ?: $fileByName;

        if (!$fileData) {
            return response()->json([
                'result' => false,
                'errors' => __('lang.file_not_found'),
            ]);
        }

        $userId = Auth::id();
        $userIp = $request->ip();
        $create = FileReports::create([
            'created_by_id' => $userId,
            'created_by_ip' => $userIp,
            'updated_by_id' => $userId,
            'updated_by_ip' => $userIp,
            'file_id' => $fileData->id,
            'file_uploader' => $fileData->created_by_id,
            'reporter' => $request->input('email'),
            'reason' => $request->input('reason'),
        ]);

        if ($create) {
            return response()->json([
                'result' => true,
                'data' => __('lang.report_send'), 
            ]);
        }

        return response()->json([
            'result' => false,
            'data' => __('lang.report_send_error'), 
        ]);
    }

    private function checkPermission(
        string $fileKey
    ): bool {
        if (Auth::check() && Auth::user()->type == 2) {
            $permission = true;
        } else {
            $filesArr = request()->session()->get('files');

            if (isset($filesArr) && $filesArr) {
                $decryptedArr = [];
                foreach ($filesArr as $file) {
                    try {
                        $decrypted = Crypt::decryptString($file);
                        array_push($decryptedArr, $decrypted);
                    } catch (DecryptException $e) {
                        // Ignore errors
                    }
                }
    
                $permission = in_array($fileKey, $decryptedArr)
                    ? true
                    : false;
            } else {
                $permission = false;
            }
        }

        return $permission;
    }

    private function randomKey() {
        $characters = 'abcdefghijklmnopqrstuvwxyz';
        $charactersNumber = strlen($characters);
        $codeLength = 8;
    
        $code = '';
        while (strlen($code) < $codeLength) {
            $position = rand(0, $charactersNumber - 1);
            $character = $characters[$position];
            $code = $code.$character;
        }
    
        return $code;
    }

}
