#!/usr/bin/env php
<?php

/*
 * Fresns (https://fresns.org)
 * Copyright (C) 2021-Present Jevan Tang
 * Released under the Apache-2.0 License.
 */

// command prefix start with
$usableCommands = [
    'db:s', // db:seed, not db:wipe
    'test',
    'migrate',

    'fresns',
    'new',
    'custom',
    'make',
    'plugin',
];

// find laravel project directory
$rootDir = $workDir = getcwd();
while (1) {
    if (file_exists($rootDir . DIRECTORY_SEPARATOR . 'bootstrap' . DIRECTORY_SEPARATOR . 'app.php')) {
        break;
    }

    $pos = strrpos($rootDir, DIRECTORY_SEPARATOR);
    if ($pos === false) {
        echo "Can't find laravel project in current path" . PHP_EOL;
        echo "You should run 'plugin' under a laravel project" . PHP_EOL;
        return 1;
    }

    $rootDir = substr($rootDir, 0, strrpos($rootDir, DIRECTORY_SEPARATOR));
}

if (!file_exists($rootDir . '/vendor/autoload.php')) {
    echo "You should run composer install first";
    return 1;
}

$startPos = strpos($workDir, DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR);
if ($startPos === false) {
    $workDir = $rootDir;
}

while ($startPos != false) {
    if (file_exists($workDir . DIRECTORY_SEPARATOR . 'composer.json')) {
        break;
    }

    $pos = strrpos($workDir, DIRECTORY_SEPARATOR);
    if ($pos === false) {
        $workDir = $rootDir;
        return 1;
    }

    $workDir = substr($workDir, 0, strrpos($workDir, DIRECTORY_SEPARATOR));
}

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/

define('LARAVEL_START', microtime(true));

require $rootDir . '/vendor/autoload.php';
/** @var \Illuminate\Foundation\Application */
$app = require_once $rootDir . '/bootstrap/app.php';

$asPlugin = $workDir !== $rootDir;
$input = new Symfony\Component\Console\Input\ArgvInput;
$grabCommand = $input->getFirstArgument();
if (is_null($grabCommand)) {
    $grabCommand = '';
}

if (!\Illuminate\Support\Str::startsWith($grabCommand, $usableCommands)) {
    $asPlugin = false;
}

// change path for plugin
if ($asPlugin) {
    $pluginFskey = substr($workDir, strrpos($workDir, DIRECTORY_SEPARATOR) + 1);
    echo "Work Plugin: " . $pluginFskey . PHP_EOL;

    $composer = json_decode(file_get_contents($workDir . DIRECTORY_SEPARATOR . 'composer.json'), true);

    if ($classNamespace = array_search('src', $composer['autoload']['psr-4'], true)) {
        $classNamespace = substr($classNamespace, 0, -1);
    } else {
        $classNamespace = array_keys($composer['autoload']['psr-4'])[0];
        $classNamespace = \Illuminate\Support\Str::before($classNamespace, '\\');
        $classNamespace .= '\\' . \Illuminate\Support\Str::studly($pluginFskey);
    }

    unset($composer);

    $app->useAppPath($workDir . '/app');
    $app->useDatabasePath($workDir . '/database');
    $app->pluginClassNamespace = $classNamespace;

    // inject namespace
    $property = new ReflectionProperty($app, 'namespace');
    $property->setAccessible(true);
    $property->setValue($app, $classNamespace . '\\');
    $property->setAccessible(false);

    require __DIR__ . '/../src/Workaround/TestMakeCommand.php';
    require __DIR__ . '/../src/Workaround/FactoryMakeCommand.php';
    require __DIR__ . '/../src/Workaround/SeedCommand.php';
    require __DIR__ . '/../src/Workaround/SeederMakeCommand.php';
    require __DIR__ . '/../src/Workaround/TestCommand.php';
}

/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);

$status = $kernel->handle($input, new Symfony\Component\Console\Output\ConsoleOutput);

// make:controller workaround for plugin
if ($asPlugin && $grabCommand === 'make:controller' && $input->getArgument('name')) {
    $fileName = $workDir . '/app/Http/Controllers/' . str_replace('\\', DIRECTORY_SEPARATOR, $input->getArgument('name')) . '.php';
    $content = file_get_contents($fileName);

    if (strpos($content, 'use App\Http\Controllers\Controller;') === false) {
        $content = str_replace(
            "use Illuminate\Http\Request;",
            "use Illuminate\Http\Request;\nuse App\Http\Controllers\Controller;",
            $content
        );
    }

    file_put_contents($fileName, $content);
}

// make:request workaround for laravel and plugin
if ($grabCommand === 'make:request' && $input->getArgument('name')) {
    $fileName = $workDir . '/app/Http/Requests/' . str_replace('\\', DIRECTORY_SEPARATOR, $input->getArgument('name')) . '.php';
    $content = file_get_contents($fileName);

    if (strpos($content, 'use App\Http\Controllers\Controller;') === false) {
        $content = str_replace(
            "return false;",
            "return true;",
            $content
        );

        $content = str_replace(
            <<<"TXT"
                public function rules(): array
                {
                    return [
                        //
                    ];
                }
            TXT,
            <<<'TXT'
                public function rules(): array
                {
                    return match (\request()->route()->getActionMethod()) {
                        default => [],
                    };
                }
            
                public function attributes(): array
                {
                    return [
                        //
                    ];
                }
            TXT,
            $content
        );
    }

    file_put_contents($fileName, $content);
}

/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running, we will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/

$kernel->terminate($input, $status);

exit($status);
