<?php

namespace Mtc\Modules\BlockRegistry\Console\Commands;

use Illuminate\Console\Command;
use Mtc\Modules\BlockRegistry\Models\BlockRegistry;
use Mtc\Modules\BlockRegistry\Services\BlockSyncService;

class BlocksDiffCommand extends Command
{
    protected $signature = 'blocks:diff {slug? : Show detailed diff for a specific block}';
    protected $description = 'Show differences between database blocks and JSON files';

    public function handle(BlockSyncService $syncService): int
    {
        $slug = $this->argument('slug');

        if ($slug) {
            return $this->showDetailedDiff($syncService, $slug);
        }

        return $this->showOverview($syncService);
    }

    protected function showOverview(BlockSyncService $syncService): int
    {
        $status = $syncService->getSyncStatus();

        if (empty($status)) {
            $this->info('No blocks found in database or JSON files.');
            return 0;
        }

        $rows = [];
        foreach ($status as $item) {
            $statusLabel = match ($item['status']) {
                'in_sync' => '<fg=green>In Sync</>',
                'local_changes' => '<fg=yellow>Local Changes</>',
                'not_exported' => '<fg=blue>Not Exported</>',
                'not_imported' => '<fg=magenta>Not Imported</>',
                'error' => '<fg=red>Error</>',
                default => $item['status'],
            };

            $rows[] = [
                $item['name'],
                $item['slug'],
                $item['category'] ?? '-',
                $statusLabel,
            ];
        }

        $this->table(['Name', 'Slug', 'Category', 'Status'], $rows);

        // Summary
        $counts = collect($status)->groupBy('status')->map->count();
        $this->newLine();
        $this->info('Summary:');
        if ($counts->get('in_sync', 0) > 0) {
            $this->line("  <fg=green>{$counts['in_sync']} in sync</>");
        }
        if ($counts->get('local_changes', 0) > 0) {
            $this->line("  <fg=yellow>{$counts['local_changes']} with local changes</>");
        }
        if ($counts->get('not_exported', 0) > 0) {
            $this->line("  <fg=blue>{$counts['not_exported']} not exported</>");
        }
        if ($counts->get('not_imported', 0) > 0) {
            $this->line("  <fg=magenta>{$counts['not_imported']} not imported</>");
        }
        if ($counts->get('error', 0) > 0) {
            $this->line("  <fg=red>{$counts['error']} with errors</>");
        }

        return 0;
    }

    protected function showDetailedDiff(BlockSyncService $syncService, string $slug): int
    {
        $block = BlockRegistry::where('slug', $slug)->first();
        $dir = $syncService->getBlocksDirectory();
        $filePath = $dir . '/' . $slug . '.json';

        if (!$block && !file_exists($filePath)) {
            $this->error("Block '{$slug}' not found in database or JSON files.");
            return 1;
        }

        if (!$block) {
            $this->warn("Block '{$slug}' exists only in JSON (not imported).");
            return 0;
        }

        if (!file_exists($filePath)) {
            $this->warn("Block '{$slug}' exists only in database (not exported).");
            return 0;
        }

        try {
            $jsonData = $syncService->readBlockFile($filePath);
        } catch (\Exception $e) {
            $this->error("Failed to read JSON: " . $e->getMessage());
            return 1;
        }

        $diff = $syncService->diffBlock($block, $jsonData);

        if (empty($diff)) {
            $this->info("Block '{$slug}' is in sync.");
            return 0;
        }

        $this->info("Diff for '{$slug}':");
        $this->newLine();

        // Metadata changes
        if (!empty($diff['metadata'])) {
            $this->line('<fg=yellow>Metadata changes:</>');
            foreach ($diff['metadata'] as $key => $change) {
                $dbVal = is_null($change['db']) ? 'null' : (string) $change['db'];
                $jsonVal = is_null($change['json']) ? 'null' : (string) $change['json'];
                $this->line("  {$key}: <fg=red>{$dbVal}</> => <fg=green>{$jsonVal}</>");
            }
            $this->newLine();
        }

        // Field changes
        if (!empty($diff['fields'])) {
            $this->line('<fg=yellow>Field changes:</>');

            if (!empty($diff['fields']['added'])) {
                foreach ($diff['fields']['added'] as $name) {
                    $this->line("  <fg=green>+ {$name}</>");
                }
            }
            if (!empty($diff['fields']['removed'])) {
                foreach ($diff['fields']['removed'] as $name) {
                    $this->line("  <fg=red>- {$name}</>");
                }
            }
            if (!empty($diff['fields']['modified'])) {
                foreach ($diff['fields']['modified'] as $name => $changes) {
                    $this->line("  <fg=yellow>~ {$name}</>");
                    $this->renderFieldChanges($changes, '    ');
                }
            }
            $this->newLine();
        }

        // Template assignment changes
        if (!empty($diff['template_assignments'])) {
            $this->line('<fg=yellow>Template assignment changes:</>');
            if (!empty($diff['template_assignments']['added'])) {
                foreach ($diff['template_assignments']['added'] as $name) {
                    $this->line("  <fg=green>+ {$name}</>");
                }
            }
            if (!empty($diff['template_assignments']['removed'])) {
                foreach ($diff['template_assignments']['removed'] as $name) {
                    $this->line("  <fg=red>- {$name}</>");
                }
            }
        }

        return 0;
    }

    protected function renderFieldChanges(array $changes, string $indent = ''): void
    {
        foreach ($changes as $key => $change) {
            if ($key === 'sub_fields') {
                $this->line("{$indent}<fg=yellow>sub_fields:</>");
                if (!empty($change['added'])) {
                    foreach ($change['added'] as $name) {
                        $this->line("{$indent}  <fg=green>+ {$name}</>");
                    }
                }
                if (!empty($change['removed'])) {
                    foreach ($change['removed'] as $name) {
                        $this->line("{$indent}  <fg=red>- {$name}</>");
                    }
                }
                if (!empty($change['modified'])) {
                    foreach ($change['modified'] as $name => $subChanges) {
                        $this->line("{$indent}  <fg=yellow>~ {$name}</>");
                        $this->renderFieldChanges($subChanges, $indent . '    ');
                    }
                }
                continue;
            }

            $dbVal = is_null($change['db']) ? 'null' : json_encode($change['db']);
            $jsonVal = is_null($change['json']) ? 'null' : json_encode($change['json']);
            $this->line("{$indent}{$key}: <fg=red>{$dbVal}</> => <fg=green>{$jsonVal}</>");
        }
    }
}
