<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Services\UserStatsService;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class SyncArtworkCreatedAtCommand extends Command
{
    public function __construct(private readonly UserStatsService $userStats)
    {
        parent::__construct();
    }

    protected $signature = 'artworks:sync-created-at
        {--chunk=500 : Number of artworks to process per batch}
        {--only-null : Update only artworks whose created_at is null}
        {--dry-run : Preview changes without writing updates}';

    protected $description = 'Copy artworks.published_at into artworks.created_at for published artworks.';

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

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

        $query = DB::table('artworks')
            ->select(['id', 'user_id', 'created_at', 'published_at'])
            ->whereNotNull('published_at')
            ->orderBy('id');

        if ($onlyNull) {
            $query->whereNull('created_at');
        }

        $processed = 0;
        $updated = 0;
        $unchanged = 0;

        $affectedUserIds = [];

        $query->chunkById($chunk, function (Collection $rows) use (&$processed, &$updated, &$unchanged, &$affectedUserIds, $dryRun): void {
            foreach ($rows as $row) {
                $processed++;

                $publishedAt = $this->normalizeTimestamp($row->published_at ?? null);
                $createdAt = $this->normalizeTimestamp($row->created_at ?? null);

                if ($publishedAt === null) {
                    $unchanged++;
                    continue;
                }

                if ($createdAt === $publishedAt) {
                    $unchanged++;
                    continue;
                }

                if ($dryRun) {
                    $this->line(sprintf(
                        '[dry] Would update artwork id=%d created_at %s => %s',
                        (int) $row->id,
                        $createdAt ?? '<null>',
                        $publishedAt
                    ));
                    $updated++;
                    continue;
                }

                DB::table('artworks')
                    ->where('id', (int) $row->id)
                    ->update([
                        'created_at' => $publishedAt,
                        'updated_at' => now()->toDateTimeString(),
                    ]);

                $affectedUserIds[(int) $row->user_id] = true;
                $updated++;
                $this->line(sprintf('[update] artwork id=%d created_at => %s', (int) $row->id, $publishedAt));
            }
        }, 'id');

        if (! $dryRun) {
            foreach (array_keys($affectedUserIds) as $userId) {
                $this->userStats->recomputeUser((int) $userId);
            }
        }

        $this->info(sprintf('Finished. processed=%d updated=%d unchanged=%d', $processed, $updated, $unchanged));

        return self::SUCCESS;
    }

    private function normalizeTimestamp(mixed $value): ?string
    {
        if ($value === null || $value === '') {
            return null;
        }

        try {
            return Carbon::parse((string) $value)->toDateTimeString();
        } catch (\Throwable) {
            return null;
        }
    }
}