<?php

declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

class ImportLegacyNewsCommentsCommand extends Command
{
    protected $signature = 'news:comments-import-legacy
                            {--dry-run : Preview only — no writes to DB}
                            {--chunk=500 : Rows to process per batch}
                            {--skip-empty : Skip comments with empty or whitespace-only content}
                            {--table= : Override legacy source table name (defaults to auto-detect news_comment/news_comments)}';

    protected $description = 'Import legacy news comments into news_article_comments';

    public function handle(): int
    {
        $dryRun = (bool) $this->option('dry-run');
        $chunk = max(1, (int) $this->option('chunk'));
        $skipEmpty = (bool) $this->option('skip-empty');

        try {
            DB::connection('legacy')->getPdo();
        } catch (\Throwable $exception) {
            $this->error('Cannot connect to legacy database: ' . $exception->getMessage());

            return self::FAILURE;
        }

        $legacyTable = $this->resolveLegacyTable();
        if ($legacyTable === null) {
            $this->error('Legacy table `news_comment` or `news_comments` was not found.');

            return self::FAILURE;
        }

        if (! DB::getSchemaBuilder()->hasTable('news_article_comments')) {
            $this->error('Target table `news_article_comments` is missing. Run migrations first.');

            return self::FAILURE;
        }

        if (! DB::getSchemaBuilder()->hasColumn('news_articles', 'legacy_news_id')) {
            $this->error('Column `news_articles.legacy_news_id` is missing. Run migrations first.');

            return self::FAILURE;
        }

        if ($dryRun) {
            $this->warn('[DRY-RUN] No data will be written.');
        }

        $articleMap = DB::table('news_articles')
            ->whereNotNull('legacy_news_id')
            ->pluck('id', 'legacy_news_id')
            ->mapWithKeys(fn ($articleId, $legacyId): array => [(int) $legacyId => (int) $articleId])
            ->all();

        $validUserIds = DB::table('users')
            ->whereNull('deleted_at')
            ->pluck('id')
            ->flip()
            ->all();

        $alreadyImported = DB::table('news_article_comments')
            ->whereNotNull('legacy_id')
            ->pluck('legacy_id')
            ->flip()
            ->all();

        $total = DB::connection('legacy')->table($legacyTable)->count();
        if ($total === 0) {
            $this->warn('No legacy news comments found.');

            return self::SUCCESS;
        }

        $stats = [
            'imported' => 0,
            'skipped_duplicate' => 0,
            'skipped_article' => 0,
            'skipped_empty' => 0,
            'users_unmapped' => 0,
            'errors' => 0,
        ];
        $touchedArticleIds = [];

        DB::connection('legacy')
            ->table($legacyTable)
            ->orderBy('comment_id')
            ->chunk($chunk, function ($rows) use (&$alreadyImported, $articleMap, $validUserIds, $dryRun, $skipEmpty, &$stats, &$touchedArticleIds): void {
                $inserts = [];

                foreach ($rows as $row) {
                    $legacyId = (int) ($row->comment_id ?? 0);
                    $legacyNewsId = (int) ($row->news_id ?? 0);
                    $legacyUserId = (int) ($row->user_id ?? 0);
                    $body = trim((string) ($row->message ?? ''));

                    if ($legacyId < 1) {
                        $stats['errors']++;
                        continue;
                    }

                    if (isset($alreadyImported[$legacyId])) {
                        $stats['skipped_duplicate']++;
                        continue;
                    }

                    if ($body === '') {
                        if ($skipEmpty) {
                            $stats['skipped_empty']++;
                            continue;
                        }

                        $body = '[no content]';
                    }

                    $articleId = $articleMap[$legacyNewsId] ?? null;
                    if (! $articleId) {
                        $stats['skipped_article']++;
                        continue;
                    }

                    $resolvedUserId = isset($validUserIds[$legacyUserId]) ? $legacyUserId : null;
                    if ($resolvedUserId === null && $legacyUserId > 0) {
                        $stats['users_unmapped']++;
                    }

                    $timestamp = $this->normalizeTimestamp($row->posted ?? null);
                    $authorName = trim((string) ($row->author ?? ''));

                    $record = [
                        'legacy_id' => $legacyId,
                        'legacy_user_id' => $legacyUserId > 0 ? $legacyUserId : null,
                        'article_id' => $articleId,
                        'user_id' => $resolvedUserId,
                        'parent_id' => null,
                        'author_name' => $authorName !== '' ? $authorName : null,
                        'body' => $body,
                        'rendered_body' => nl2br(e($body)),
                        'status' => 'visible',
                        'legacy_posted_at' => $timestamp,
                        'created_at' => $timestamp,
                        'updated_at' => $timestamp,
                        'deleted_at' => null,
                    ];

                    if (! $dryRun) {
                        $inserts[] = $record;
                        $alreadyImported[$legacyId] = true;
                        $touchedArticleIds[$articleId] = $articleId;
                    }

                    $stats['imported']++;
                }

                if (! $dryRun && $inserts !== []) {
                    try {
                        DB::table('news_article_comments')->insert($inserts);
                    } catch (\Throwable) {
                        foreach ($inserts as $insert) {
                            try {
                                DB::table('news_article_comments')->insertOrIgnore([$insert]);
                            } catch (\Throwable) {
                                $stats['errors']++;
                            }
                        }
                    }
                }
            });

        if (! $dryRun && $touchedArticleIds !== []) {
            DB::table('news_articles')
                ->whereIn('id', array_values($touchedArticleIds))
                ->update(['comments_enabled' => true]);
        }

        $this->table(
            ['Result', 'Count'],
            [
                ['Imported', $stats['imported']],
                ['Skipped - already imported', $stats['skipped_duplicate']],
                ['Skipped - article missing', $stats['skipped_article']],
                ['Skipped - empty body', $stats['skipped_empty']],
                ['Imported with unmapped user', $stats['users_unmapped']],
                ['Errors', $stats['errors']],
            ]
        );

        return $stats['errors'] > 0 ? self::FAILURE : self::SUCCESS;
    }

    private function resolveLegacyTable(): ?string
    {
        $configured = trim((string) $this->option('table'));
        if ($configured !== '') {
            return DB::connection('legacy')->getSchemaBuilder()->hasTable($configured) ? $configured : null;
        }

        foreach (['news_comment', 'news_comments'] as $candidate) {
            if (DB::connection('legacy')->getSchemaBuilder()->hasTable($candidate)) {
                return $candidate;
            }
        }

        return null;
    }

    private function normalizeTimestamp(mixed $value): string
    {
        $raw = trim((string) ($value ?? ''));

        if ($raw === '' || str_starts_with($raw, '0000-00-00')) {
            return now()->toDateTimeString();
        }

        try {
            return Carbon::parse($raw)->toDateTimeString();
        } catch (\Throwable) {
            return now()->toDateTimeString();
        }
    }
}