<?php

namespace App\Helpers;

use App\Models\Upload;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use App\Helpers\PlanHelper;
use App\Helpers\NudityHelper;
use Illuminate\Support\Facades\Log;

class UploadRestUrlHelper
{
    private static $defaultStorage;

    public function __construct() 
    {
        self::$defaultStorage = defaultStorage()->storage_key;
    }

    public static function upload(
        string $fileUrl, 
        array $formData
    ): array {
        $request = request();
        $token = $request->header('token');

        if (!$token) {
            return [
                false,
                'User token is missing.'
            ];
        }

        $userData = DB::table('users')
            ->where('api_token', $token)
            ->first();

        if (!$userData) {
            return [
                false,
                'User token is wrong.'
            ];
        }

        $fileName = pathinfo($fileUrl, PATHINFO_BASENAME) ?? false;
        $fileExt = pathinfo($fileUrl, PATHINFO_EXTENSION) ?? false;
        
        if (!$fileName || !$fileExt) {
            return [
                false,
                'The file URL is incorrect.',
            ];
        }

        $fileSize = self::remoteFileSize($fileUrl);
        $fileSize = $fileSize / 1024;
        $allowedTypes = uploadableTypes('array');

        if (!in_array($fileExt, $allowedTypes)) {
            return [
                false,
                'You cannot upload this type of file.',
            ];
        }

        $fileHeaders = @get_headers($fileUrl);
        if(
            strpos($fileHeaders[0], '403') 
            || strpos($fileHeaders[0], '404') 
            || strpos($fileHeaders[0], '500')
            || strpos($fileHeaders[0], '504')
        ) {
            return [
                false,
                'File could not be retrieved from external source.',
            ];
        }

        $maxSize = config('upload.MAX_FILE_SIZE');
        if ($fileSize > $maxSize) {
            $maxSize = formatKiloBytes($maxSize);
            return [
                false,
                "The maximum file size can be {$maxSize}"
            ];
        }

        $canIRest = PlanHelper::canIRest(
            $userData->id, 
        );

        if (!$canIRest[0]) {
            return [
                false,
                $canIRest[1], 
            ];
        }

        $canIUpload = PlanHelper::canIUpload(
            $userData->id, 
            $fileName, 
            $fileSize
        );

        if (!$canIUpload[0]) {
            return [
                false,
                $canIUpload[1], 
            ];
        }

        $contents = file_get_contents($fileUrl);
        if (!$contents) {
            return [
                false,
                'File could not be retrieved from external source.',
            ];
        }

        $fileRandom = Str::random(40);
        $fileName = "{$fileRandom}.{$fileExt}";
        $upload = Storage::disk('temp')->put($fileName, $contents);

        if (!$upload) {
            return [
                false,
                'The file could not be uploaded.',
            ];
        }

        $nudityChecker = setting('nudity_status');
        if ($nudityChecker == 1) {
            $nudityCheck = NudityHelper::check($fileName);
            if (!$nudityCheck[0]) {
                return [
                    false,
                    $nudityCheck[1], 
                ];
            }
        }

        $manipulate = self::start(
            $fileName,
            $formData,
            $userData->id,
        );

        if ($manipulate[0]) {
            return [
                true,
                url("get/{$manipulate[1]}"),
                url("file/{$manipulate[1]}"),
            ];
        } else {
            Storage::disk('temp')
                ->delete($fileName);

            return [
                false,
                $manipulate[1], 
            ];
        }
    }

    public static function start(
        string $fileName, 
        array $formData,
        int $userId,
    ): array {
        $database = self::database(
            $fileName,
            $formData,
            $userId,
        );

        if ($database[0]) {
            return [
                true,
                $database[1],
            ];
        } else {
            return [
                false,
                $database[1],
            ];
        }

    }

    public static function database(
        string $fileName, 
        array $formData,
        int $userId,
    ): array {
        $request = request();

        if (!Storage::disk('temp')->exists($fileName)) {
            return [
                false, 
                'File not found.'
            ];
        }

        $userIp = $request->ip();
        $fileNameArr = explode('.', $fileName);
        $fileSize = Storage::disk('temp')
            ->size($fileName);

        $fileData['created_by_id'] = $userId;
        $fileData['created_by_ip'] = $userIp;
        $fileData['updated_by_id'] = $userId;
        $fileData['updated_by_ip'] = $userIp;
        $fileData['filename'] = $fileName;
        $fileData['filesize'] = $fileSize;
        $fileData['filetype'] = $fileNameArr[1];
        $fileData['disk'] = self::$defaultStorage;

        if (isset($formData['auto-remove']) && $formData['auto-remove']) {
            $fileData['autoremove'] = $formData['auto-remove'];
        }

        if (isset($formData['password']) && $formData['password']) {
            $fileData['password'] = $formData['password'];
        }
        
        $create = Upload::create($fileData);

        if ($create) {

            try{
                Storage::disk(self::$defaultStorage)->put(
                    $fileName,
                    Storage::disk('temp')->get($fileName)
                );

                Storage::disk('temp')->delete($fileName);

                return [
                    true, 
                    $fileName,
                ];
            } catch (\Exception $e) {
                Log::error($e);
                Upload::where('id', $create->id)->delete();
                return [
                    false,
                    'The file could not be uploaded.',
                ];
            }
        }

        return [
            false, 
            'The file could not be uploaded.',
        ];
    }
    
    private static function remoteFileSize(string $fileUrl): mixed {
        // Get all header information
        $fileData = get_headers($fileUrl, true);
        // Look up validity
        if (isset($fileData['Content-Length'])) {
            // Return file size
            return (int) $fileData['Content-Length'];
        }

        return false;
    }

}
