<?php

declare(strict_types=1);

namespace App\Console\Commands;

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

/**
 * Migrates legacy `artworks_comments` (projekti_old_skinbase) into `artwork_comments`.
 *
 * Column mapping:
 *   legacy.comment_id    → artwork_comments.legacy_id  (idempotency key)
 *   legacy.artwork_id    → artwork_comments.artwork_id
 *   legacy.user_id       → artwork_comments.user_id
 *   legacy.description   → artwork_comments.content
 *   legacy.date + .time  → artwork_comments.created_at / updated_at
 *
 * Ignored legacy columns: owner, author (username strings), owner_user_id
 *
 * Usage:
 *   php artisan comments:import-legacy
 *   php artisan comments:import-legacy --dry-run
 *   php artisan comments:import-legacy --chunk=1000
 *   php artisan comments:import-legacy --allow-guest-user=0  (import rows where user_id maps to 0 / not found, assigning a fallback user_id)
 */
class ImportLegacyComments extends Command
{
    protected $signature = 'comments:import-legacy
                            {--dry-run       : Preview only — no writes to DB}
                            {--chunk=500     : Rows to process per batch}
                            {--skip-empty    : Skip comments with empty/whitespace-only content}';

    protected $description = 'Import legacy artworks_comments into artwork_comments';

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

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

        // Verify legacy connection
        try {
            DB::connection('legacy')->getPdo();
        } catch (\Throwable $e) {
            $this->error('Cannot connect to legacy database: ' . $e->getMessage());
            return self::FAILURE;
        }

        if (! DB::connection('legacy')->getSchemaBuilder()->hasTable('artworks_comments')) {
            $this->error('Legacy table `artworks_comments` not found.');
            return self::FAILURE;
        }

        if (! DB::getSchemaBuilder()->hasColumn('artwork_comments', 'legacy_id')) {
            $this->error('Column `legacy_id` missing from `artwork_comments`. Run: php artisan migrate');
            return self::FAILURE;
        }

        // Pre-load valid artwork IDs and user IDs from new DB for O(1) lookup
        $this->info('Loading new-DB artwork and user ID sets…');

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

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

        $this->info(sprintf(
            'Found %d artworks and %d users in new DB.',
            count($validArtworkIds),
            count($validUserIds)
        ));

        // Already-imported legacy IDs (to resume safely)
        $this->info('Loading already-imported legacy_ids…');
        $alreadyImported = DB::table('artwork_comments')
            ->whereNotNull('legacy_id')
            ->pluck('legacy_id')
            ->flip()
            ->all();

        $this->info(sprintf('%d comments already imported (will be skipped).', count($alreadyImported)));

        $total = DB::connection('legacy')->table('artworks_comments')->count();
        $this->info("Legacy rows to process: {$total}");

        if ($total === 0) {
            $this->warn('No legacy rows found. Nothing to do.');
            return self::SUCCESS;
        }

        $stats = [
            'imported'          => 0,
            'skipped_duplicate' => 0,
            'skipped_artwork'   => 0,
            'skipped_user'      => 0,
            'skipped_empty'     => 0,
            'errors'            => 0,
        ];

        $bar = $this->output->createProgressBar($total);
        $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%% | imported: %imported% | skipped: %skipped%');
        $bar->setMessage('0', 'imported');
        $bar->setMessage('0', 'skipped');
        $bar->start();

        DB::connection('legacy')
            ->table('artworks_comments')
            ->orderBy('comment_id')
            ->chunk($chunk, function ($rows) use (
                &$stats,
                &$alreadyImported,
                $validArtworkIds,
                $validUserIds,
                $dryRun,
                $skipEmpty,
                $bar
            ) {
                $inserts = [];
                $now     = now();

                foreach ($rows as $row) {
                    $legacyId  = (int) $row->comment_id;
                    $artworkId = (int) $row->artwork_id;
                    $userId    = (int) $row->user_id;
                    $content   = trim((string) ($row->description ?? ''));

                    // --- Already imported ---
                    if (isset($alreadyImported[$legacyId])) {
                        $stats['skipped_duplicate']++;
                        $bar->advance();
                        continue;
                    }

                    // --- Content ---
                    if ($skipEmpty && $content === '') {
                        $stats['skipped_empty']++;
                        $bar->advance();
                        continue;
                    }

                    // Replace empty content with a placeholder so NOT NULL is satisfied
                    if ($content === '') {
                        $content = '[no content]';
                    }

                    // --- Artwork must exist ---
                    if (! isset($validArtworkIds[$artworkId])) {
                        $stats['skipped_artwork']++;
                        $bar->advance();
                        continue;
                    }

                    // --- User must exist ---
                    if (! isset($validUserIds[$userId])) {
                        $stats['skipped_user']++;
                        $bar->advance();
                        continue;
                    }

                    // --- Build timestamp from separate date + time columns ---
                    $createdAt = $this->buildTimestamp($row->date, $row->time, $now);

                    if (! $dryRun) {
                        $inserts[] = [
                            'legacy_id'   => $legacyId,
                            'artwork_id'  => $artworkId,
                            'user_id'     => $userId,
                            'content'     => $content,
                            'is_approved' => 1,
                            'created_at'  => $createdAt,
                            'updated_at'  => $createdAt,
                            'deleted_at'  => null,
                        ];

                        $alreadyImported[$legacyId] = true;
                    }

                    $stats['imported']++;
                    $bar->advance();
                }

                if (! $dryRun && ! empty($inserts)) {
                    try {
                        DB::table('artwork_comments')->insert($inserts);
                    } catch (\Throwable $e) {
                        // Fallback: row-by-row with ignore on unique violations
                        foreach ($inserts as $row) {
                            try {
                                DB::table('artwork_comments')->insertOrIgnore([$row]);
                            } catch (\Throwable) {
                                $stats['errors']++;
                            }
                        }
                    }
                }

                $skippedTotal = $stats['skipped_duplicate']
                    + $stats['skipped_artwork']
                    + $stats['skipped_user']
                    + $stats['skipped_empty'];

                $bar->setMessage((string) $stats['imported'], 'imported');
                $bar->setMessage((string) $skippedTotal, 'skipped');
            });

        $bar->finish();
        $this->newLine(2);

        // -------------------------------------------------------------------------
        // Summary
        // -------------------------------------------------------------------------
        $this->table(
            ['Result', 'Count'],
            [
                ['Imported',                    $stats['imported']],
                ['Skipped – already imported',  $stats['skipped_duplicate']],
                ['Skipped – artwork gone',       $stats['skipped_artwork']],
                ['Skipped – user gone',          $stats['skipped_user']],
                ['Skipped – empty content',      $stats['skipped_empty']],
                ['Errors',                       $stats['errors']],
            ]
        );

        if ($dryRun) {
            $this->warn('[DRY-RUN] Nothing was written. Re-run without --dry-run to apply.');
        } else {
            $this->info('Migration complete.');
        }

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

    /**
     * Combine a legacy `date` (DATE) and `time` (TIME) column into a single datetime string.
     * Falls back to $fallback when both are null.
     */
    private function buildTimestamp(mixed $date, mixed $time, \Illuminate\Support\Carbon $fallback): string
    {
        if (! $date) {
            return $fallback->toDateTimeString();
        }

        $datePart = substr((string) $date, 0, 10);         // '2000-09-13'
        $timePart = $time ? substr((string) $time, 0, 8) : '00:00:00';  // '09:34:27'

        // Sanity-check: MySQL TIME can be negative or > 24h for intervals — clamp to midnight
        if (! preg_match('/^\d{2}:\d{2}:\d{2}$/', $timePart) || $timePart < '00:00:00') {
            $timePart = '00:00:00';
        }

        return $datePart . ' ' . $timePart;
    }
}
