<?php
/**
 * Root password management command.
 *
 * @package Flowaxy\Interface\CLI\Commands
 */

declare(strict_types=1);

namespace Flowaxy\Interface\CLI\Commands;

use Flowaxy\Core\System\PathResolver;
use Flowaxy\Interface\CLI\Command;

use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function preg_quote;
use function password_hash;
use function preg_match;
use function preg_replace;
use function strlen;
use function str_ends_with;
use function str_starts_with;
use function substr;
use function trim;

final class RootPasswordCommand extends Command
{
    public function getName(): string
    {
        return 'root:password';
    }

    public function getDescription(): string
    {
        return 'Change root password stored in storage/config/system/root.ini';
    }

    public function getHelp(): string
    {
        return "Usage:\n"
            . "  php index.php root:password <new_password>\n"
            . "  php index.php root:password --password=<new_password>\n";
    }

    protected function handle(array $args): int
    {
        $password = $this->extractOption($args, '--password');
        if ($password === null) {
            $password = $args[0] ?? null;
        }

        $password = $password !== null ? trim((string) $password) : '';
        if ($password === '') {
            $this->error('Password is required. Use --password=... or pass as first argument.');
            return 1;
        }

        $rootIni = PathResolver::storageConfig() . DS . 'system' . DS . 'root.ini';
        if (!file_exists($rootIni)) {
            $this->error("Root config not found: {$rootIni}");
            return 1;
        }

        $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
        if ($hash === false) {
            $this->error('Failed to hash password.');
            return 1;
        }

        $content = file_get_contents($rootIni);
        if ($content === false) {
            $this->error("Failed to read: {$rootIni}");
            return 1;
        }

        // Update password_hash inside [root] section, preserving file formatting as much as possible.
        $updated = $this->replaceIniValueInSection($content, 'root', 'password_hash', '"' . $hash . '"');
        if ($updated === null) {
            $this->error("Failed to update [root] password_hash in {$rootIni}");
            return 1;
        }

        if (file_put_contents($rootIni, $updated) === false) {
            $this->error("Failed to write: {$rootIni}");
            return 1;
        }

        $this->output('OK: root password updated.');
        return 0;
    }

    /**
     * @param array<int, string> $args
     */
    private function extractOption(array $args, string $name): ?string
    {
        foreach ($args as $arg) {
            if ($arg === $name) {
                continue;
            }
            if (str_starts_with($arg, $name . '=')) {
                return (string) substr($arg, strlen($name) + 1);
            }
        }
        return null;
    }

    private function replaceIniValueInSection(string $ini, string $section, string $key, string $value): ?string
    {
        // Find section block
        $pattern = '/(\[' . preg_quote($section, '/') . '\]\s*)([\s\S]*?)(\n\[[^\]]+\]|\z)/m';
        if (!preg_match($pattern, $ini, $m)) {
            return null;
        }

        $sectionHeader = $m[1];
        $sectionBody = $m[2];
        $tail = $m[3];

        $keyPattern = '/(^\s*' . preg_quote($key, '/') . '\s*=\s*).*$/' . 'm';
        if (preg_match($keyPattern, $sectionBody)) {
            $sectionBody = preg_replace($keyPattern, '$1' . $value, $sectionBody, 1);
        } else {
            // Insert at end of section body
            if ($sectionBody !== '' && !str_ends_with($sectionBody, "\n")) {
                $sectionBody .= "\n";
            }
            $sectionBody .= $key . ' = ' . $value . "\n";
        }

        return preg_replace($pattern, $sectionHeader . $sectionBody . $tail, $ini, 1);
    }
}
