<?php

namespace Ignite\Core\Http\Controllers\Api;

use Carbon\Carbon;
use Ignite\Core\Facades\Format;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Fluent;
use Illuminate\Support\Str;
use ZipArchive;

class MediaController
{
    /**
     * List the files in the configured folder on the configured disk.
     *
     * @return \Illuminate\Support\Collection
     */
    public function index()
    {
        $disk = Storage::disk(config('core.cms.disk'));

        $folder = config('core.cms.folder', 'uploads');

        $files = collect($disk->getDriver()->getAdapter()->listContents($folder))
            ->where('type', 'file')
            ->values();

        return $files->map(function ($fileInfo) use ($disk) {
            return new Fluent([
                'url' => $disk->url($path = $fileInfo['path']),
                'path' => $path,
                'name' => $basename = basename($fileInfo['path']),
                'extension' => $fileInfo['extension'] ?? Str::extension($fileInfo['path']),
                'mime' => Str::mimeType($basename),
                'size' => $size = $fileInfo['size'],
                'size_formatted' => Format::bytes($size),
                'timestamp' => $timestamp = $fileInfo['timestamp'],
                'timestamp_formatted' => Carbon::parse($timestamp)->diffForHumans(),
                'hash' => md5($path),
            ]);
        });
    }

    /**
     * Upload a file.
     *
     * @return \Illuminate\Contracts\Routing\UrlGenerator|string
     */
    public function upload()
    {
        $file = request()->file('image');
        $filename = $file->getClientOriginalName();
        $disk = config('core.cms.disk', 's3');
        $folder = config('core.cms.folder', 'uploads');

        $file = $file->storeAs($folder, $filename, [
            'disk' => $disk,
            'visibility' => 'public'
        ]);

        return Storage::disk($disk)->url("{$folder}/{$filename}");
    }

    /**
     * Download the provided files.
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
     */
    public function download(Request $request)
    {
        $filename = md5($request->input('files')) . '.zip';
        $filepath = storage_path("app/public/cms/{$filename}");
        $download = asset("/storage/cms/{$filename}");

        if (file_exists($filepath)) {
            return response()->json([
                'status' => true,
                'url' => $download,
                'filename' => $filename
            ], 200);
        }

        $files = explode(',', $request->input('files'));
        $disk = Storage::disk(config('core.cms.disk', 's3'));
        $folder = config('core.cms.folder', 'uploads');
        $results = collect($disk->files($folder))->filter(function ($file) use ($files) {
            return in_array(md5($file), $files);
        });

        if (! File::exists(storage_path("app/public/cms"))) {
            File::makeDirectory(storage_path("app/public/cms"));
        }

        $zip = new ZipArchive();
        $open = $zip->open($filepath, ZipArchive::CREATE);

        if ($open === true) {
            $results->each(function ($file) use ($disk, $zip) {
                $zip->addFromString($file, $disk->get($file));
            });

            $zip->close();

            return response()->json([
                'status' => true,
                'url' => $download,
                'filename' => $filename
            ], 200);
        } else {
            return response()->json(['status' => false], 500);
        }
    }

    /**
     * Delete the provided files by their hash.
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function destroy(Request $request)
    {
        $files = explode(',', $request->input('files'));

        $disk = Storage::disk(config('core.cms.disk'));
        $folder = config('core.cms.folder', 'uploads');

        $results = collect($disk->files($folder))->filter(function ($file) use ($files) {
            return in_array(md5($file), $files);
        });

        $type = ucwords(Str::plural('file', $results->count()));

        if ($results->isEmpty()) {
            $status = false;
            $message = "None of the selected files were found.";
        } else {
            $status = $disk->delete($results->toArray());
            $message = "{$type} deleted successfully.";
        }

        return response()->json(compact('files', 'status', 'message'), $status ? 200 : 500);
    }
}
