<?php
/**
 * Delete config key/section in storage/config/*.ini.
 *
 * @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 array_key_exists;
use function file_exists;
use function file_put_contents;
use function is_array;
use function parse_ini_file;
use function preg_match;
use function str_contains;
use function str_replace;
use function trim;

final class ConfigDeleteCommand extends Command
{
    public function getName(): string
    {
        return 'config:delete';
    }

    public function getDescription(): string
    {
        return 'Delete a key or a whole section from an ini file under storage/config';
    }

    public function getHelp(): string
    {
        return "Usage:\n"
            . "  php index.php config:delete <relative_ini_path> <section> <key>\n"
            . "  php index.php config:delete <relative_ini_path> <section>\n";
    }

    protected function handle(array $args): int
    {
        $rel = trim((string)($args[0] ?? ''));
        $section = trim((string)($args[1] ?? ''));
        $key = trim((string)($args[2] ?? ''));

        if ($rel === '' || str_contains($rel, '..')) {
            $this->error('relative_ini_path is required and must not contain ".."');
            return 1;
        }
        if ($section === '') {
            $this->error('section is required');
            return 1;
        }

        $file = PathResolver::storageConfig() . DS . str_replace(['/', '\\'], DS, $rel);
        if (!file_exists($file)) {
            $this->error("Config file not found: {$file}");
            return 1;
        }

        $data = parse_ini_file($file, true, INI_SCANNER_RAW);
        if (!is_array($data)) {
            $this->error("Failed to parse ini: {$file}");
            return 1;
        }

        if (!isset($data[$section]) || !is_array($data[$section])) {
            $this->error("Section not found: [{$section}]");
            return 1;
        }

        if ($key === '') {
            unset($data[$section]);
            $ini = $this->serializeIni($data);
            if (file_put_contents($file, $ini) === false) {
                $this->error("Failed to write: {$file}");
                return 1;
            }
            $this->output("OK: deleted section [{$section}] from {$rel}");
            return 0;
        }

        if (!array_key_exists($key, $data[$section])) {
            $this->error("Key not found: [{$section}] {$key}");
            return 1;
        }

        unset($data[$section][$key]);
        $ini = $this->serializeIni($data);
        if (file_put_contents($file, $ini) === false) {
            $this->error("Failed to write: {$file}");
            return 1;
        }

        $this->output("OK: deleted [{$section}] {$key} from {$rel}");
        return 0;
    }

    /**
     * @param array<string, mixed> $data
     */
    private function serializeIni(array $data): string
    {
        $out = "; Auto-generated by Flowaxy CLI\n; Do not edit manually if you're not sure\n\n";
        foreach ($data as $section => $pairs) {
            if (!is_array($pairs)) {
                continue;
            }
            $out .= '[' . $section . ']' . "\n";
            foreach ($pairs as $k => $v) {
                $out .= $k . ' = ' . $this->iniValue($v) . "\n";
            }
            $out .= "\n";
        }
        return $out;
    }

    private function iniValue(mixed $value): string
    {
        if ($value === true) {
            return 'true';
        }
        if ($value === false) {
            return 'false';
        }
        if ($value === null) {
            return 'null';
        }
        $s = (string) $value;
        $s = str_replace(["\r", "\n"], ['\\r', '\\n'], $s);
        if (preg_match('/[^a-zA-Z0-9_\-\.]/', $s)) {
            $s = str_replace('"', '\"', $s);
            return '"' . $s . '"';
        }
        return $s;
    }
}
