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

require __DIR__ . '/vendor/autoload.php';

use Core\Database;
use Dotenv\Dotenv;
use Core\ViewRenderer;
use Core\Migration;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$command = $argv[1] ?? null;

switch ($command) {
    case 'migrate':
        migrate();
        break;
    case 'create:migration':
        $name = $argv[2] ?? null;
        createMigration($name);
        break;
    case 'seed':
        seed();
        break;
    case 'controller':
        $name = $argv[2] ?? null;
        $viewRouteFlag = $argv[3] ?? null;
        createController($name, $viewRouteFlag);
        break;
    case 'model':
        $name = $argv[2] ?? null;
        createModel($name);
        break;
    case 'service':
        $name = $argv[2] ?? null;
        createService($name);
        break;
    case 'repository':
        $name = $argv[2] ?? null;
        createRepository($name);
        break;
    case 'tailwind:init':
        initTailwind();
        break;
    case 'dump-autoload':
        dumpAutoload();
        break;
    case 'material:init':
        initMaterialUI();
        break;
    case 'serve':
        serve();
        break;
    case 'react:init':
        initReact();
        buildReact();
        updateLayout('react');
        break;
    case 'vue:init':
        initVue();
        buildVue();
        updateLayout('vue');
        break;
    case 'react:build':
        buildReact();
        break;
    case 'vue:build':
        buildVue();
        break;
    case 'typescript:init':
        initTypeScript();
        break;
    case 'js:init':
        initJavaScript();
        break;
    default:
        echo "Invalid command.\n";
        break;
}

function migrate()
{
    try {
        Database::connect();
        echo "Database connection successful.\n";
    } catch (PDOException $e) {
        echo "Database connection failed: " . $e->getMessage() . "\n";
        exit(1);
    }

    foreach (glob(__DIR__ . '/database/migrations/*.php') as $migrationFile) {
        require_once $migrationFile;
        $class = basename($migrationFile, '.php');
        $className = preg_replace('/^[0-9_]+/', '', $class);
        $className = str_replace('_', '', ucwords($className, '_'));

        if (class_exists($className)) {
            $migration = new $className();
            $migration->up();
            echo "Migrated: " . $className . "\n";
        } else {
            echo "Class does not exist: " . $className . "\n";
        }
    }
}

function createMigration($name)
{
    if ($name) {
        $timestamp = date('Y_m_d_His');
        $className = 'Create' . ucfirst($name) . 'Table';
        $fileName = "{$timestamp}_create_{$name}_table.php";
        $migrationTemplate = <<<EOT
<?php

use Core\Migration;

class {$className}
{
    public function up()
    {
        \$migration = new Migration();
        \$migration->createTable('{$name}', function (\$table) {
            \$table->id();
            \$table->string('name');
            \$table->timestamps();
        });
    }
}
EOT;
        file_put_contents(__DIR__ . "/database/migrations/{$fileName}", $migrationTemplate);
        echo "Migration created successfully: {$fileName}\n";
    } else {
        echo "Migration name is required.\n";
    }
}

function seed()
{
    try {
        Database::connect();
        echo "Database connection successful.\n";
    } catch (PDOException $e) {
        echo "Database connection failed: " . $e->getMessage() . "\n";
        exit(1);
    }

    foreach (glob(__DIR__ . '/database/seeds/*.php') as $seedFile) {
        require_once $seedFile;
        $class = basename($seedFile, '.php');
        if (class_exists($class)) {
            $seeder = new $class();
            $seeder->run();
            echo "Seeded: " . $class . "\n";
        }
    }
}

function createController($name, $viewRouteFlag)
{
    $lname = strtolower($name);
    if ($name) {
        $useReact = file_exists(__DIR__ . '/../config/react_initialized');
        $useVue = file_exists(__DIR__ . '/../config/vue_initialized');

        $controllerTemplate = <<<EOT
<?php

namespace App\Controllers;

use Core\Controller;
use Core\Request;
use Core\Response;
use Core\ViewRenderer;

class {$name}Controller extends Controller
{
    public function index(Request \$request, Response \$response)
    {
        \$viewRenderer = new ViewRenderer('{$lname}/index', [
            'title' => '{$name} Page',
            'message' => 'Welcome to My Bolt Framework!',
            'layout' => 'layout'
        ]);
        \$viewRenderer->render();
    }
}
EOT;

        if ($useReact || $useVue) {
            $controllerTemplate = <<<EOT
<?php

namespace App\Controllers;

use Core\Controller;
use Core\Request;
use Core\Response;
use Core\ViewRenderer;

class {$name}Controller extends Controller
{
    public function index(Request \$request, Response \$response)
    {
        \$viewRenderer = new ViewRenderer('{$lname}/index', [
            'title' => '{$name} Page',
            'message' => 'Welcome to My Bolt Framework!',
            'layout' => 'layout',
            'useReact' => $useReact,
            'useVue' => $useVue,
            'componentProps' => ['message' => 'Welcome to My Bolt Framework!']
        ]);
        \$viewRenderer->render();
    }

    public function renderReactComponent()
    {
        \$viewRenderer = new ViewRenderer('', []);
        \$viewRenderer->renderReactComponent('MyReactComponent', [
            'message' => 'Welcome to My Bolt Framework!'
        ]);
    }

    public function renderVueComponent()
    {
        \$viewRenderer = new ViewRenderer('', []);
        \$viewRenderer->renderVueComponent('MyVueComponent', [
            'message' => 'Welcome to My Bolt Framework!'
        ]);
    }
}
EOT;
        }

        file_put_contents(__DIR__ . "/app/Controllers/{$name}Controller.php", $controllerTemplate);
        echo "{$name}Controller created successfully.\n";

        if ($viewRouteFlag == '-v') {
            // Create the view directory
            $viewDir = __DIR__ . "/app/Views/{$lname}";
            if (!is_dir($viewDir)) {
                mkdir($viewDir, 0755, true);
            }

            $viewTemplate = <<<EOT

    <main>
        <h1><?= \$message ?? 'Welcome to My Bolt Framework!' ?></h1>
        <p>This is the {$name} view.</p>
    </main>
   
EOT;

            if ($useReact) {
                $viewTemplate .= <<<EOT

    <div id="react-root"></div>
    <script>
        window.REACT_APP_PROPS = <?= json_encode(\$componentProps) ?>;
    </script>
    <script src="/react-app/build/static/js/main.js"></script>
EOT;
            }

            if ($useVue) {
                $viewTemplate .= <<<EOT

    <div id="vue-root"></div>
    <script>
        window.VUE_APP_PROPS = <?= json_encode(\$componentProps) ?>;
    </script>
    <script src="/vue-app/dist/js/app.js"></script>
EOT;
            }

            file_put_contents("{$viewDir}/index.php", $viewTemplate);
            echo "View for {$name}Controller created successfully.\n";

            // Add the route
            $routeTemplate = <<<EOT
\$router->get('/{$lname}', [App\Controllers\\{$name}Controller::class, 'index']);
EOT;

            if ($useReact) {
                $routeTemplate .= <<<EOT
\$router->get('/{$lname}/react', [App\Controllers\\{$name}Controller::class, 'renderReactComponent']);
EOT;
            }

            if ($useVue) {
                $routeTemplate .= <<<EOT
\$router->get('/{$lname}/vue', [App\Controllers\\{$name}Controller::class, 'renderVueComponent']);
EOT;
            }

            file_put_contents(__DIR__ . "/routes/web.php", $routeTemplate . PHP_EOL, FILE_APPEND);
            echo "Route for {$name}Controller added to web.php successfully.\n";
        }
    } else {
        echo "Controller name is required.\n";
    }
}


function createModel($name)
{
    if ($name) {
        $modelTemplate = <<<EOT
<?php

namespace App\Models;

use Core\Model;

class {$name} extends Model
{
    protected \$fillable = [];
}
EOT;
        file_put_contents(__DIR__ . "/app/Models/{$name}.php", $modelTemplate);
        echo "{$name} model created successfully.\n";
    } else {
        echo "Model name is required.\n";
    }
}

function createService($name)
{
    if ($name) {
        $serviceTemplate = <<<EOT
<?php

namespace App\Services;

use App\Repositories\\{$name}Repository;

class {$name}Service
{
    protected \$repository;

    public function __construct({$name}Repository \$repository)
    {
        \$this->repository = \$repository;
    }

    public function getAll{$name}s()
    {
        return \$this->repository->findAll();
    }

    public function get{$name}ById(\$id)
    {
        return \$this->repository->find(\$id);
    }

    public function create{$name}(\$data)
    {
        return \$this->repository->create(\$data);
    }

    public function update{$name}(\$id, \$data)
    {
        return \$this->repository->update(\$id, \$data);
    }

    public function delete{$name}(\$id)
    {
        return \$this->repository->delete(\$id);
    }
}
EOT;
        file_put_contents(__DIR__ . "/app/Services/{$name}Service.php", $serviceTemplate);
        echo "{$name}Service created successfully.\n";
    } else {
        echo "Service name is required.\n";
    }
}

function createRepository($name)
{
    if ($name) {
        $repositoryTemplate = <<<EOT
<?php

namespace App\Repositories;

use Core\Repository;
use App\Models\\{$name};

class {$name}Repository extends Repository
{
    public function __construct()
    {
        parent::__construct(new {$name}());
    }
}
EOT;
        file_put_contents(__DIR__ . "/app/Repositories/{$name}Repository.php", $repositoryTemplate);
        echo "{$name}Repository created successfully.\n";
    } else {
        echo "Repository name is required.\n";
    }
}

function initTailwind()
{
    // Node.js ve npm gereklidir
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    // Tailwind CSS ve bağımlılıkları yükle
    echo "Installing Tailwind CSS and dependencies...\n";
    exec('npm install tailwindcss postcss postcss-cli autoprefixer');

    // Tailwind CSS yapılandırma dosyasını oluştur
    echo "Creating Tailwind CSS configuration file...\n";
    exec('npx tailwindcss init');

    // tailwind.config.js dosyasını oluştur ve güncelle
    echo "Updating tailwind.config.js file...\n";
    $tailwindConfig = <<<EOT
module.exports = {
  content: [
    './app/Views/**/*.php',
    './app/Views/*.php',
    './public/**/*.html',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
EOT;
    file_put_contents(__DIR__ . '/tailwind.config.js', $tailwindConfig);

    // postcss.config.js dosyasını oluştur
    echo "Creating postcss.config.js file...\n";
    $postcssConfig = <<<EOT
module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
  ],
}
EOT;
    file_put_contents(__DIR__ . '/postcss.config.js', $postcssConfig);

    // styles.css dosyasını oluştur
    echo "Creating src/styles.css file...\n";
    if (!is_dir(__DIR__ . '/src')) {
        mkdir(__DIR__ . '/src', 0755, true);
    }
    $stylesCss = <<<EOT
@tailwind base;
@tailwind components;
@tailwind utilities;
EOT;
    file_put_contents(__DIR__ . '/src/styles.css', $stylesCss);

    // package.json'a script ekle
    echo "Adding build script to package.json...\n";
    $packageJson = json_decode(file_get_contents(__DIR__ . '/package.json'), true);
    $packageJson['scripts']['build:css'] = 'npx postcss src/styles.css -o public/css/styles.css';
    file_put_contents(__DIR__ . '/package.json', json_encode($packageJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));

    // CSS'i derle
    echo "Building CSS...\n";
    exec('npm run build:css');

    echo "Tailwind CSS initialized successfully.\n";
}

function dumpAutoload()
{
    echo "Dumping autoload...\n";
    exec('composer dump-autoload');
    echo "Autoload dumped successfully.\n";
}

function serve()
{
    $port = getenv('APP_PORT') ?: 8080;
    $host = 'localhost';
    echo "Starting server on http://$host:$port\n";
    exec("php -S $host:$port -t public");
}

function initMaterialUI()
{
    // Ensure Node.js and npm are installed
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    // Install Material UI and dependencies
    echo "Installing Material UI and dependencies...\n";
    exec('npm install @mui/material @emotion/react @emotion/styled');

    // Install Roboto font
    echo "Installing Roboto font...\n";
    exec('npm install @fontsource/roboto');

    // Install Material Icons
    echo "Installing Material UI Icons...\n";
    exec('npm install @mui/icons-material');

    echo "Material UI initialized successfully.\n";
}


function initReact()
{
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    echo "Initializing React app...\n";
    exec('npx create-react-app public/react-app', $output, $return_var);
    if ($return_var !== 0) {
        echo "Failed to initialize React app. Error: " . implode("\n", $output) . "\n";
        return;
    }

    echo "Installing Material-UI...\n";
    exec('cd public/react-app && npm install @mui/material @emotion/react @emotion/styled', $output, $return_var);
    if ($return_var !== 0) {
        echo "Failed to install Material-UI. Error: " . implode("\n", $output) . "\n";
        return;
    }

    echo "React app with Material-UI initialized successfully.\n";

    // Create a marker file
    file_put_contents(__DIR__ . '/../config/react_initialized', 'true');
}



function initVue()
{
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    echo "Installing Vue CLI...\n";
    exec('npm install -g @vue/cli');

    echo "Creating Vue project...\n";
    exec('vue create public/vue-app');

    echo "Vue initialized successfully.\n";

    // Create a marker file
    file_put_contents(__DIR__ . '/../config/vue_initialized', 'true');
}


function buildReact()
{
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    echo "Building React app...\n";
    exec('cd public/react-app && npm run build');
    echo "React app built successfully.\n";
}

function buildVue()
{
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    echo "Building Vue.js app...\n";
    exec('cd public/vue-app && npm run build');
    echo "Vue.js app built successfully.\n";
}

function updateLayout($framework)
{
    $layoutFile = __DIR__ . '/../app/Views/layout.php';
    $layoutContent = file_get_contents($layoutFile);

    if ($framework === 'react') {
        $scriptTag = '<script src="/react-app/build/static/js/main.js"></script>';
        if (!strpos($layoutContent, $scriptTag)) {
            $layoutContent = str_replace('</body>', "$scriptTag\n</body>", $layoutContent);
        }
    } elseif ($framework === 'vue') {
        $scriptTag = '<script src="/vue-app/dist/js/app.js"></script>';
        if (!strpos($layoutContent, $scriptTag)) {
            $layoutContent = str_replace('</body>', "$scriptTag\n</body>", $layoutContent);
        }
    }

    file_put_contents($layoutFile, $layoutContent);
    echo "Layout updated for {$framework}.\n";
}

function initTypeScript()
{
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    echo "Installing TypeScript and dependencies...\n";
    exec('npm install typescript @types/node @types/react @types/react-dom @types/jest');

    echo "Creating tsconfig.json...\n";
    $tsconfig = <<<EOT
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}
EOT;
    file_put_contents(__DIR__ . '/tsconfig.json', $tsconfig);

    echo "TypeScript initialized successfully.\n";
}

function initJavaScript()
{
    if (!shell_exec('which npm')) {
        echo "Node.js and npm are required. Please install them first.\n";
        exit(1);
    }

    echo "Initializing JavaScript project...\n";
    exec('npm init -y');

    echo "JavaScript initialized successfully.\n";
}