<?php

namespace Daylight\Core\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class TranslationsGenerateCommand extends Command
{
    protected $signature = 'daylight:translations:generate
        {--dry : Do not write files, just show summary}
        {--locales=en,nl : Locales to generate (comma-separated)}';

    protected $description = 'Scan the codebase and generate key-based locale files (EN/NL) and a migration map.';

    public function handle(): int
    {
        $locales = array_filter(array_map('trim', explode(',', (string) ($this->option('locales') ?? 'en,nl'))));
        if (empty($locales)) {
            $locales = ['en', 'nl'];
        }
        $dryRun = (bool) $this->option('dry');

        $paths = [
            base_path('resources/views'),
            base_path('resources/assets/js'),
            base_path('src'),
        ];

        $foundStrings = [];
        foreach ($this->expandFiles($paths) as $file) {
            $content = @file_get_contents($file);
            if ($content === false) {
                continue;
            }
            $isBlade = str_ends_with($file, '.blade.php');
            $isVue = str_ends_with($file, '.vue');

            foreach ([
                '/__\(\s*[\"\']([^\"\']+)[\"\']\s*\)/u',
                '/@lang\(\s*[\"\']([^\"\']+)[\"\']\s*\)/u',
                '/trans\(\s*[\"\']([^\"\']+)[\"\']\s*\)/u',
            ] as $regex) {
                if (preg_match_all($regex, $content, $m)) {
                    foreach ($m[1] as $str) {
                        if (Str::startsWith($str, 'daylight::')) {
                            continue;
                        }
                        if ($this->looksLikeKey($str)) {
                            continue;
                        }
                        $foundStrings[] = ['file' => $file, 'string' => $str];
                    }
                }
            }

            if ($isBlade || $isVue) {
                if (preg_match_all('/>([^<]+)</u', $content, $tm)) {
                    foreach ($tm[1] as $txt) {
                        $raw = trim($txt);
                        if ($raw === '') {
                            continue;
                        }
                        if (str_contains($raw, '{{') || str_contains($raw, '}}') || Str::startsWith($raw, '@')) {
                            continue;
                        }
                        if (! preg_match('/[\p{L}]/u', $raw)) {
                            continue;
                        }
                        if (mb_strlen($raw) > 70) {
                            continue;
                        }
                        $foundStrings[] = ['file' => $file, 'string' => $raw];
                    }
                }
            }
        }

        $foundStrings = collect($foundStrings)
            ->unique(fn ($e) => $e['string'])
            ->values()
            ->all();

        $map = [];
        $perGroup = [];
        foreach ($foundStrings as $entry) {
            $original = $entry['string'];
            $group = $this->determineGroup($entry['file']);
            $key = $this->makeKey($original);
            $baseKey = $key;
            $suffix = 1;
            while (isset($perGroup[$group][$key])) {
                $suffix++;
                $key = $baseKey . '_' . $suffix;
            }
            $perGroup[$group][$key] = $original;
            $map[$original] = "daylight::{$group}.{$key}";
        }

        $mapPath = base_path('resources/lang/migration-map.generated.json');
        $this->writeFile($mapPath, json_encode($map, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), $dryRun);

        foreach ($perGroup as $group => $entries) {
            foreach ($locales as $locale) {
                $filePath = base_path("resources/lang/{$locale}/{$group}.php");
                $existing = $this->readPhpArray($filePath);
                $flat = Arr::dot(is_array($existing) ? $existing : []);
                foreach ($entries as $key => $value) {
                    $fullKey = $key;
                    if (! array_key_exists($fullKey, $flat)) {
                        $flat[$fullKey] = $value;
                    }
                }
                $tree = $this->undot($flat);
                $this->writePhpArray($filePath, $tree, $dryRun);
            }
        }

        $summary = [
            'groups' => array_keys($perGroup),
            'counts' => collect($perGroup)->map(fn ($arr) => count($arr))->all(),
            'locales' => $locales,
            'map' => $mapPath,
        ];

        $this->line(json_encode($summary, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
        if (! $dryRun) {
            $this->info('Locale files and migration map generated.');
        }

        return 0;
    }

    private function determineGroup(string $file): string
    {
        $lower = strtolower($file);

        return match (true) {
            str_contains($lower, DIRECTORY_SEPARATOR . 'store' . DIRECTORY_SEPARATOR) => 'store',
            str_contains($lower, DIRECTORY_SEPARATOR . 'settings' . DIRECTORY_SEPARATOR) => 'settings',
            str_contains($lower, DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR) => 'content',
            default => 'general',
        };
    }

    private function makeKey(string $text): string
    {
        $normalized = preg_replace('/:([A-Za-z0-9_]+)/', '$1', $text) ?? $text;
        $normalized = preg_replace('/[^\p{L}\p{N}\s]+/u', ' ', $normalized) ?? $normalized;
        $normalized = preg_replace('/\s+/', ' ', $normalized) ?? $normalized;
        $slug = Str::slug(mb_strtolower(trim($normalized)), '_');

        return $slug === '' ? 'text' : $slug;
    }

    private function looksLikeKey(string $str): bool
    {
        return str_contains($str, '.') && ! str_contains($str, ' ');
    }

    private function readPhpArray(string $path): array
    {
        if (! file_exists($path)) {
            return [];
        }
        try {
            $data = include $path;

            return is_array($data) ? $data : [];
        } catch (\Throwable) {
            return [];
        }
    }

    private function undot(array $flat): array
    {
        $result = [];
        foreach ($flat as $k => $v) {
            Arr::set($result, $k, $v);
        }

        return $result;
    }

    private function writePhpArray(string $path, array $data, bool $dryRun): void
    {
        $export = var_export($data, true);
        $contents = "<?php\n\nreturn {$export};\n";
        $this->writeFile($path, $contents, $dryRun);
    }

    private function writeFile(string $path, string $contents, bool $dryRun): void
    {
        if ($dryRun) {
            $this->line("[dry] write: {$path}");

            return;
        }
        $dir = dirname($path);
        if (! is_dir($dir)) {
            @mkdir($dir, 0777, true);
        }
        file_put_contents($path, $contents);
    }

    /**
     * @param  array<int,string>      $paths
     * @return \Generator<int,string>
     */
    private function expandFiles(array $paths): \Generator
    {
        $ignoreDirs = ['vendor', 'node_modules', 'storage', 'dist', 'public', 'resources/lang'];
        foreach ($paths as $path) {
            if (! is_string($path) || $path === '' || ! is_dir($path)) {
                continue;
            }
            $it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS));
            foreach ($it as $fileInfo) {
                /** @var \SplFileInfo $fileInfo */
                $filePath = $fileInfo->getPathname();
                $relParts = explode(DIRECTORY_SEPARATOR, str_replace(base_path() . DIRECTORY_SEPARATOR, '', $filePath));
                if (count(array_intersect($ignoreDirs, $relParts)) > 0) {
                    continue;
                }
                $lower = strtolower($filePath);
                if (str_ends_with($lower, '.blade.php') || str_ends_with($lower, '.php') || str_ends_with($lower, '.js') || str_ends_with($lower, '.vue')) {
                    yield $filePath;
                }
            }
        }
    }
}
