<?php

namespace App\Http\Controllers\Admin\Files;

use App\Models\File;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\FileUploadRequest;
use App\Models\Setting;
use App\Services\Admin\Files\FilesService;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use Intervention\Image\ImageManager;
use Inertia\Inertia;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\Encoders\WebpEncoder;
use Intervention\Image\Encoders\GifEncoder;
use Intervention\Image\Encoders\JpegEncoder;
use Intervention\Image\Encoders\PngEncoder;

class FilesController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request, FilesService $filesService)
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();

        return Inertia::render('Admin/Files/List', [
            'files' => $filesService->getFiles($request, $user)
        ]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(FileUploadRequest $request)
    {
        /** @var \App\Models\User $user */
        $user = auth()->user();

        // check folders
        try {
            $this->fixMediaFolders();
        } catch (Exception $e) {
        }

        $errors = [];
        $successCount = 0;

        // common settings for all files
        $addWatermark = $request->exists('addWatermark') && $request->addWatermark;
        $cropImage    = $request->exists('cropImage') && $request->cropImage;
        $optimization = $request->exists('optimization') && $request->optimization;

        // get watermark
        $watermarkUrl = null;
        if ($addWatermark) {
            $watermarkSetting = Setting::where('key', 'watermark')->first();
            if ($watermarkSetting) {
                $watermarkData = @unserialize($watermarkSetting->value);
                if (is_array($watermarkData) && isset($watermarkData['id'], $watermarkData['url'])) {
                    $watermarkFile = File::find($watermarkData['id']);
                    if ($watermarkFile) {
                        $watermarkUrl = $watermarkData['url'];
                    }
                }
            }
            if ($watermarkUrl === null) {
                return redirect()->back()->withErrors([__('messages.watermark_not_found')]);
            }
        }

        $files = $request->file('files');
        $descriptions = $request->input('descriptions', []);

        foreach ($files as $index => $file) {
            try {
                $fileFormat = strtolower($file->getClientOriginalExtension());
                $fileType = null;

                switch ($fileFormat) {
                    case "jpeg":
                    case "jpg":
                    case "png":
                    case "gif":
                    case "webp":
                        $fileType = "image";
                        break;
                    case "svg":
                        $fileType = "svg";
                        break;
                    case "pdf":
                        $fileType = "pdf";
                        break;
                    case "zip":
                        $fileType = "zip";
                        break;
                    case "mp3":
                        $fileType = "audio";
                        break;
                    case "mp4":
                        $fileType = "video";
                        break;
                    default:
                        $errors[] = __('messages.file_type_not_supported', ['name' => $file->getClientOriginalName()]);
                        continue 2;
                }

                // current file name
                $description = $descriptions[$index] ?? null;

                $fileName = 'file.' . time() . '.' . rand(10000, 99999) . '.' . $file->getClientOriginalExtension();
                $fileSize = floor($file->getSize() / 1000);
                $fileSaveAddressNoName = 'library/' . date('Y-m-d') . '/' . $user->id;
                $fileSaveAddress = $fileSaveAddressNoName . '/' . $fileName;
                $imageResolution = null;

                if ($fileType == "image") {
                    try {
                        $imageResolution = getimagesize($file)[0] . '×' . getimagesize($file)[1];
                    } catch (Exception $e) {
                    }

                    $imageTemp = null;

                    try {
                        $manager = ImageManager::withDriver(new Driver());
                        $imageTemp = $manager->read($file->path());
                    } catch (Exception $e) {
                        $errors[] = __('messages.image_driver_error');
                        continue;
                    }

                    if ($cropImage) {
                        try {
                            if ($imageTemp->height() >= $imageTemp->width()) {
                                $imageTemp->cover($imageTemp->width(), $imageTemp->width());
                            } else {
                                $imageTemp->cover($imageTemp->height(), $imageTemp->height());
                            }
                        } catch (Exception $e) {
                            $errors[] = __('messages.image_crop_error');
                        }
                    }

                    if ($addWatermark && $watermarkUrl) {
                        try {
                            $imageTemp->place(
                                public_path($watermarkUrl),
                                'bottom-right',
                                30,
                                30,
                                100
                            );
                        } catch (\Exception $e) {
                            $errors[] = __('messages.watermark_error');
                        }
                    }

                    // check temp image
                    if ($imageTemp === null) {
                        $errors[] = __('messages.image_driver_error');
                        continue;
                    }

                    // image variables
                    try {
                        if ($fileFormat == 'gif') {
                            $fileFormat = 'gif';
                            $fileSaveAddressImage = $fileSaveAddressNoName . '/' . 'file.' . time() . '.' . rand(10000, 99999) . '.' . $fileFormat;
                            $finalImageTemp = $imageTemp->encode(new GifEncoder())->__toString();
                            $fileName = basename($fileSaveAddressImage);
                        } else {
                            $fileFormat = 'webp';
                            $fileSaveAddressImage = $fileSaveAddressNoName . '/' . 'file.' . time() . '.' . rand(10000, 99999) . '.' . $fileFormat;
                            $optimizationPercent = $optimization ? 80 : 100;
                            $encodedImage = $imageTemp->encode(new WebpEncoder($optimizationPercent))->__toString();
                            $fileSize = strlen($encodedImage) / 1000;
                            $finalImageTemp = $encodedImage;
                            $fileName = basename($fileSaveAddressImage);
                        }
                    } catch (\Exception $e) {
                        $errors[] = 'خطا: ' . $e->getMessage();
                        continue;
                    }

                    $uploadResult = Storage::disk('media')->put($fileSaveAddressImage, $finalImageTemp, 'public');
                    if ($uploadResult) {
                        $user->files()->create([
                            'name' => $fileName,
                            'url' => '/media/' . $fileSaveAddressImage,
                            'description' => $description,
                            'extension' => $fileFormat,
                            'size' => $fileSize,
                            'resolution' => $imageResolution,
                            'type' => $fileType,
                        ]);
                        $successCount++;
                    } else {
                        $errors[] = __('messages.unknown_error');
                    }
                } else {
                    $uploadResult = '/media/' . $fileSaveAddress;
                    Storage::disk('media')->put($fileSaveAddress, file_get_contents($file));

                    if ($uploadResult) {
                        $user->files()->create([
                            'name' => $fileName,
                            'url' => $uploadResult,
                            'description' => $description,
                            'extension' => $fileFormat,
                            'size' => $fileSize,
                            'resolution' => $imageResolution,
                            'type' => $fileType == 'svg' ? 'image' : $fileType,
                        ]);
                        $successCount++;
                    } else {
                        $errors[] = __('messages.unknown_error');
                    }
                }
            } catch (\Exception $e) {
                $errors[] = __('messages.file_upload_error', [
                    'name' => $file->getClientOriginalName(),
                    'error' => $e->getMessage()
                ]);
            }
        }

        if ($successCount > 0) {
            $message = trans_choice('messages.files_uploaded', $successCount, ['count' => $successCount]);
            return redirect()->back()->with('message', [$message])->withErrors($errors);
        }

        return redirect()->back()->withErrors($errors);
    }

    /**
     * Display the specified resource.
     */
    public function show(File $file)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(File $file)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, File $file)
    {
        $request->validate([
            'description' => 'required'
        ]);


        $file->update([
            'description' => $request->description
        ]);

        return redirect()->back()->with('message', [__('messages.file_updated')]);
    }

    /**
     * replace image
     */
    public function replace(Request $request, File $file)
    {
        $user = auth()->user();
        if ($file->user_id != $user->id && $user->type != 'owner') {
            return redirect()->back()->withErrors([__('messages.file_is_not_valid_for_user')]);
        }

        if ($file->type !== 'image') {
            return redirect()->back()->withErrors([__('messages.replace_only_for_images')]);
        }

        $request->validate([
            'file'          => 'required|file|mimes:jpg,jpeg,png,gif,svg,webp|max:51200',
            'optimization'  => 'boolean',
            'cropImage'     => 'boolean',
            'addWatermark'  => 'boolean',
        ]);

        $optimization = $request->boolean('optimization');
        $cropImage    = $request->boolean('cropImage');
        $addWatermark = $request->boolean('addWatermark');

        $watermarkUrl = null;
        if ($addWatermark) {
            $watermarkSetting = Setting::where('key', 'watermark')->first();
            if ($watermarkSetting) {
                $watermarkData = @unserialize($watermarkSetting->value);
                if (is_array($watermarkData) && isset($watermarkData['id'], $watermarkData['url'])) {
                    $watermarkFile = File::find($watermarkData['id']);
                    if ($watermarkFile) {
                        $watermarkUrl = $watermarkData['url'];
                    }
                }
            }
            if ($watermarkUrl === null) {
                return redirect()->back()->withErrors([__('messages.watermark_not_found')]);
            }
        }

        $baseUrl = strtok($file->url, '?');
        $oldRelativePath = ltrim(str_replace('/media/', '', $baseUrl), '/');

        Storage::disk('media')->delete($oldRelativePath);

        $uploadedFile = $request->file('file');
        $originalExtension = strtolower($uploadedFile->getClientOriginalExtension());

        if (!in_array($originalExtension, ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'])) {
            return redirect()->back()->withErrors([__('messages.file_type_not_supported')]);
        }

        if (in_array($originalExtension, ['svg', 'gif'])) {
            $newRelativePath = preg_replace('/\.[^.]+$/', '.' . $originalExtension, $oldRelativePath);
            $newBaseUrl = '/media/' . $newRelativePath;

            Storage::disk('media')->put($newRelativePath, file_get_contents($uploadedFile));
            $fileSize = floor($uploadedFile->getSize() / 1000);

            $file->update([
                'url'        => $newBaseUrl . '?v=' . now()->timestamp,
                'extension'       => $originalExtension,
                'size'       => $fileSize,
                'resolution' => null,
            ]);
            Cache::forget('files_' . $file->id);
            return redirect()->back()->with('message', [__('messages.image_replaced')]);
        }

        try {
            $manager = ImageManager::withDriver(new Driver());
            $imageTemp = $manager->read($uploadedFile->path());
        } catch (Exception $e) {
            return redirect()->back()->withErrors([__('messages.image_driver_error')]);
        }

        if ($cropImage) {
            try {
                if ($imageTemp->height() >= $imageTemp->width()) {
                    $imageTemp->cover($imageTemp->width(), $imageTemp->width());
                } else {
                    $imageTemp->cover($imageTemp->height(), $imageTemp->height());
                }
            } catch (Exception $e) {
                return redirect()->back()->withErrors([__('messages.image_crop_error')]);
            }
        }

        if ($addWatermark && $watermarkUrl) {
            try {
                $imageTemp->place(public_path($watermarkUrl), 'bottom-right', 30, 30, 100);
            } catch (\Exception $e) {
                return redirect()->back()->withErrors([__('messages.watermark_error')]);
            }
        }

        $saveExtension = strtolower(pathinfo($oldRelativePath, PATHINFO_EXTENSION));

        $encoder = null;
        switch ($saveExtension) {
            case 'jpg':
            case 'jpeg':
                $encoder = new JpegEncoder($optimization ? 80 : 100);
                break;
            case 'png':
                $encoder = new PngEncoder();
                break;
            case 'gif':
                $encoder = new GifEncoder();
                break;
            case 'webp':
                $encoder = new WebpEncoder($optimization ? 80 : 100);
                break;
            default:
                $saveExtension = 'webp';
                $oldRelativePath = preg_replace('/\.[^.]+$/', '.webp', $oldRelativePath);
                $encoder = new WebpEncoder($optimization ? 80 : 100);
                break;
        }

        try {
            $encodedImage = $imageTemp->encode($encoder)->__toString();
            $fileSize = strlen($encodedImage) / 1000;
        } catch (\Exception $e) {
            return redirect()->back()->withErrors(['خطا: ' . $e->getMessage()]);
        }

        $uploadResult = Storage::disk('media')->put($oldRelativePath, $encodedImage, 'public');

        if ($uploadResult) {
            $imageResolution = null;
            try {
                $imageResolution = getimagesize($uploadedFile)[0] . '×' . getimagesize($uploadedFile)[1];
            } catch (Exception $e) {
            }

            $file->update([
                'url'        => $baseUrl . '?v=' . now()->timestamp,
                'size'       => $fileSize,
                'resolution' => $imageResolution,
            ]);

            Cache::forget('files_' . $file->id);

            return redirect()->back()->with('message', [__('messages.image_replaced')]);
        }

        return redirect()->back()->withErrors([__('messages.unknown_error')]);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(File $file)
    {
        $user = auth()->user();
        if ($file->user_id == $user->id || $user->type == 'owner') {

            $url = $file->url;
            $relativePath = ltrim(str_replace('/media/', '', $url), '/');
            Storage::disk('media')->delete($relativePath);

            $file->delete();

            return redirect()->back()->with('message', [__('messages.file_deleted')]);
        }

        return redirect()->back()->withErrors([__('messages.file_is_not_valid_for_user')]);
    }

    /**
     * fix folders permission
     */
    private function fixMediaFolders()
    {
        $disk = Storage::disk('media');
        $rootPath = $disk->path(''); // مسیر root storage/app/media

        $this->checkFolders($rootPath);
    }

    /**
     * check folders permission
     */
    private function checkFolders($path)
    {
        // فقط پوشه‌ها
        $folders = glob($path . '/*', GLOB_ONLYDIR);

        foreach ($folders as $folder) {
            $perm = substr(sprintf('%o', fileperms($folder)), -3);

            // اگر پرمیشن غیر از 755 بود
            if ($perm !== '755') {
                @chmod($folder, 0755);
            }

            // بررسی پوشه‌های داخل این پوشه به صورت بازگشتی
            $this->checkFolders($folder);
        }
    }
}
