<?php

namespace App\Http\Controllers\Api\Common;

use App\Classes\Common;
use App\Classes\LangTrans;
use App\Http\Controllers\ApiBaseController;
use Examyou\RestAPI\ApiResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Nwidart\Modules\Facades\Module;
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Client;
use Illuminate\Support\Arr;
use ZipArchive;

class ModuleController extends ApiBaseController
{
    public function index()
    {
        $modulesData = Common::moduleInformations();

        return ApiResponse::make('Data fetched', $modulesData);
    }

    public function updateStatus(Request $request)
    {
        $moduleName = $request->verified_name;
        $checked = $request->checked;

        $module = Module::find($moduleName);
        // $moduleName = $module->getName() ? $module->getName() :  $moduleName;

        if ($checked) {
            $module->enable();

            // Run module migrations
            try {
                Artisan::call('module:migrate', ['module' => $moduleName, '--force' => true]);
            } catch (\Exception $e) {
                \Log::warning('Failed to run migrations for module ' . $moduleName . ': ' . $e->getMessage());
            }

            // Seed module translations
            try {
                LangTrans::seedModuleTranslations($moduleName);
            } catch (\Exception $e) {
                \Log::warning('Failed to seed translations for module ' . $moduleName . ': ' . $e->getMessage());
            }
        } else {
            $module->disable();
        }

        $modulesData = Common::moduleInformations();

        return ApiResponse::make('Success', $modulesData);
    }

    public function install(Request $request)
    {
        $response = Http::post('https://envato.codeifly.com/install', [
            'verified_name' => $request->verified_name,
            'domain' => $request->domain,
        ]);

        $responseData = $response->object();

        $tempPath = storage_path() . '/app';
        $fileName = $request->verified_name . '.zip';
        $tempFileName = $tempPath . '/' . $fileName;

        $fileHandler = fopen($tempFileName, 'w');

        $fileUrl = $responseData->url;

        $client = new Client();
        $client->request('GET', $fileUrl,  [
            'sink' => $fileHandler,
            'progress' => function ($downloadTotalSize, $downloadTotalSoFar, $uploadTotalSize, $uploadSizeSoFar) {
                $percentageDownloaded = ($downloadTotalSize > 0) ? (($downloadTotalSoFar / $downloadTotalSize) * 100) : 0;
                File::put(public_path() . '/download-percentage.txt', $percentageDownloaded);
            },
            'verify' => false
        ]);

        $modulesData = Common::moduleInformations();

        return ApiResponse::make('Success', $modulesData);
    }

    public function extractZip(Request $request)
    {
        $moduleName = $request->verified_name;

        // Check if it's a manual upload (stored in modules folder)
        if ($moduleName === 'manual_upload') {
            $fileName = $request->file_name;
            $tempFileName = storage_path('app/modules/' . $fileName);
        } else {
            $tempPath = storage_path() . '/app';
            $fileName = $request->verified_name . '.zip';
            $tempFileName = $tempPath . '/' . $fileName;
        }

        if (!File::exists($tempFileName)) {
            throw new \Examyou\RestAPI\Exceptions\ApiException('Module file not found: ' . $tempFileName);
        }

        // Extract to base path (zip contains Modules/ and public/ folders)
        $extractPath = base_path();
        $modulesPath = base_path('Modules');

        // Ensure Modules directory exists
        if (!File::exists($modulesPath)) {
            File::makeDirectory($modulesPath, 0755, true);
        }

        // Get existing module directories before extraction (for manual uploads)
        $directoriesBefore = [];
        if ($moduleName === 'manual_upload') {
            $directoriesBefore = File::directories($modulesPath);
        }

        try {
            $zip = new ZipArchive;
            $result = $zip->open($tempFileName);

            if ($result !== true) {
                throw new \Exception('Failed to open ZIP file. Error code: ' . $result);
            }

            if (!$zip->extractTo($extractPath)) {
                $zip->close();
                throw new \Exception('Failed to extract ZIP file');
            }

            $zip->close();
        } catch (\Exception $e) {
            throw new \Examyou\RestAPI\Exceptions\ApiException('Failed to extract ZIP file: ' . $e->getMessage());
        }

        // Get the actual module name from the extracted folder if it's a manual upload
        if ($moduleName === 'manual_upload') {
            // Get directories after extraction
            $directoriesAfter = File::directories($modulesPath);

            // Find the new directory by comparing before and after
            $newDirectories = array_diff($directoriesAfter, $directoriesBefore);

            if (count($newDirectories) > 0) {
                $newDir = reset($newDirectories); // Get the first new directory
                $actualModuleName = basename($newDir);
            } else {
                throw new \Examyou\RestAPI\Exceptions\ApiException('Failed to extract module. No new module directory found. This might happen if the ZIP file structure is incorrect or the module already exists.');
            }
        } else {
            $actualModuleName = $moduleName;
        }

        // Verify module exists before proceeding
        $moduleExists = Module::find($actualModuleName);
        if (!$moduleExists) {
            throw new \Examyou\RestAPI\Exceptions\ApiException('Module "' . $actualModuleName . '" was not found after extraction. Please check the ZIP file structure.');
        }

        try {
            LangTrans::seedTranslations($actualModuleName);
        } catch (\Exception $e) {
            // Log but don't fail - translations are optional
            \Log::warning('Failed to seed translations for module ' . $actualModuleName . ': ' . $e->getMessage());
        }

        sleep(3);

        try {
            Artisan::call('module:migrate', ['module' => $actualModuleName, '--force' => true]);
        } catch (\Exception $e) {
            throw new \Examyou\RestAPI\Exceptions\ApiException('Failed to run migrations for module ' . $actualModuleName . ': ' . $e->getMessage());
        }

        $modulesData = Common::moduleInformations();

        // Delete the uploaded zip file after successful installation
        if ($moduleName === 'manual_upload' && File::exists($tempFileName)) {
            File::delete($tempFileName);
        }

        return ApiResponse::make('Success', [
            'installed_modules' => $modulesData['installed_modules'],
            'enabled_modules' => Arr::pluck($modulesData['enabled_modules'], 'verified_name'),
            'verified_name' => $actualModuleName,
            'version'    => $this->getModuleVersion($actualModuleName)
        ]);
    }

    public function getModuleVersion($moduleName)
    {
        $module = Module::find($moduleName);

        if ($module) {
            $modulePath = $module->getPath();
            $versionFileName = app_type() == 'saas' ? 'superadmin_version.txt' : 'version.txt';
            $version = File::get($modulePath . '/' . $versionFileName);

            return preg_replace("/\r|\n/", "", $version);
        }

        return "-";
    }

    public function downloadPercent(Request $request)
    {
        $percentage = File::get(public_path() . '/download-percentage.txt');

        return ApiResponse::make('Success', [
            'percentage' => $percentage
        ]);
    }

    public function manualUpload(Request $request)
    {
        $request->validate([
            'file' => 'required|file|mimes:zip,application/zip,application/x-zip-compressed|max:204800', // Max 200MB
        ]);

        try {
            if (!$request->hasFile('file')) {
                throw new \Examyou\RestAPI\Exceptions\ApiException('No file uploaded');
            }

            $file = $request->file('file');

            if (!$file->isValid()) {
                throw new \Examyou\RestAPI\Exceptions\ApiException('File upload failed');
            }

            $fileName = 'manual_module_' . time() . '_' . $file->getClientOriginalName();

            // Ensure the modules directory exists
            $uploadsDir = storage_path('app/modules');
            if (!File::exists($uploadsDir)) {
                File::makeDirectory($uploadsDir, 0755, true);
            }

            // Move the file to storage/app/modules folder
            $fullPath = $uploadsDir . '/' . $fileName;
            $file->move($uploadsDir, $fileName);

            // Verify the file was actually stored
            if (!File::exists($fullPath)) {
                throw new \Examyou\RestAPI\Exceptions\ApiException('File was not saved properly');
            }

            return ApiResponse::make('File uploaded successfully', [
                'file_name' => $fileName,
                'file_path' => 'modules/' . $fileName,
                'file_size' => File::size($fullPath),
                'full_path' => $fullPath,
                'uploaded_at' => now()->format('Y-m-d H:i:s')
            ]);
        } catch (\Exception $e) {
            throw new \Examyou\RestAPI\Exceptions\ApiException('Failed to upload file: ' . $e->getMessage());
        }
    }

    public function listUploadedFiles()
    {
        try {
            $uploadsPath = storage_path('app/modules');

            // Create directory if it doesn't exist
            if (!File::exists($uploadsPath)) {
                File::makeDirectory($uploadsPath, 0755, true);
                return ApiResponse::make('Success', ['files' => []]);
            }

            $files = File::files($uploadsPath);
            $fileList = [];

            foreach ($files as $file) {
                $fileList[] = [
                    'name' => $file->getFilename(),
                    'size' => $file->getSize(),
                    'size_formatted' => $this->formatBytes($file->getSize()),
                    'uploaded_at' => date('Y-m-d H:i:s', $file->getMTime()),
                    'path' => 'modules/' . $file->getFilename()
                ];
            }

            // Sort by upload time, newest first
            usort($fileList, function ($a, $b) {
                return strtotime($b['uploaded_at']) - strtotime($a['uploaded_at']);
            });

            return ApiResponse::make('Success', [
                'files' => $fileList
            ]);
        } catch (\Exception $e) {
            throw new \Examyou\RestAPI\Exceptions\ApiException('Failed to list files: ' . $e->getMessage());
        }
    }

    public function deleteUploadedFile($fileName)
    {
        try {
            $filePath = storage_path('app/modules/' . $fileName);

            if (!File::exists($filePath)) {
                throw new \Examyou\RestAPI\Exceptions\ApiException('File not found');
            }

            File::delete($filePath);

            return ApiResponse::make('File deleted successfully');
        } catch (\Exception $e) {
            throw new \Examyou\RestAPI\Exceptions\ApiException('Failed to delete file: ' . $e->getMessage());
        }
    }

    private function formatBytes($bytes, $precision = 2)
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];

        for ($i = 0; $bytes > 1024; $i++) {
            $bytes /= 1024;
        }

        return round($bytes, $precision) . ' ' . $units[$i];
    }
}
