<?php

namespace Modules\ActivityLog\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Modules\ActivityLog\Entities\Services\SharedLinkIndexer;

/**
 * One-time backfill for the public share-link search feature.
 *
 * For every existing row in `shared_products` it:
 *   1. Builds the searchable `shared_product_items` index (name / SKU / category).
 *   2. Creates a matching "Product Share" entry in `enhanced_activity_logs`
 *      (using the share's real created_at / user / business) so historical
 *      links are visible and filterable in the Activity Log viewer.
 *
 * Both steps are idempotent, so the command is safe to re-run. Use --fresh to
 * rebuild the item index even where it already exists.
 */
class BackfillSharedLinks extends Command
{
    protected $signature = 'activitylog:backfill-shared-links
                            {--chunk=500 : Number of share links processed per batch}
                            {--fresh : Re-index items even if a share is already indexed}
                            {--no-logs : Only build the item index, skip activity-log backfill}';

    protected $description = 'Index existing public share links by product/SKU/category and '
                           . 'backfill matching "Product Share" activity-log entries.';

    public function handle(SharedLinkIndexer $indexer): int
    {
        if (!DB::getSchemaBuilder()->hasTable('shared_products')) {
            $this->error('Table `shared_products` does not exist — nothing to backfill.');
            return 1;
        }

        $chunk      = max(1, (int) $this->option('chunk'));
        $fresh      = (bool) $this->option('fresh');
        $writeLogs  = !$this->option('no-logs');

        $total = DB::table('shared_products')->count();
        if ($total === 0) {
            $this->info('No share links found.');
            return 0;
        }

        $this->info("Backfilling {$total} share link(s)…");
        $bar = $this->output->createProgressBar($total);
        $bar->start();

        $indexed   = 0;
        $skipped   = 0;
        $logsAdded = 0;

        DB::table('shared_products')->orderBy('id')->chunkById($chunk, function ($shares) use (
            $indexer, $fresh, $writeLogs, $bar, &$indexed, &$skipped, &$logsAdded
        ) {
            foreach ($shares as $share) {
                // 1. Searchable item index ───────────────────────────────
                $alreadyIndexed = DB::table('shared_product_items')
                    ->where('shared_product_id', $share->id)
                    ->exists();

                if ($fresh || !$alreadyIndexed) {
                    $indexer->index($share->id, $share->business_id, $share->products_data);
                    $indexed++;
                } else {
                    $skipped++;
                }

                // 2. Activity-log entry ──────────────────────────────────
                if ($writeLogs) {
                    $logExists = DB::table('enhanced_activity_logs')
                        ->where('model_type', 'shared_product')
                        ->where('model_id', $share->id)
                        ->exists();

                    if (!$logExists) {
                        $this->writeActivityLog($share);
                        $logsAdded++;
                    }
                }

                $bar->advance();
            }
        });

        $bar->finish();
        $this->newLine(2);
        $this->info("Done. Indexed: {$indexed}, already-indexed (skipped): {$skipped}, activity-log entries added: {$logsAdded}.");

        return 0;
    }

    /**
     * Recreate the "Product Share" audit entry the live createPublicShare()
     * path would have written, using the share's recorded metadata.
     */
    protected function writeActivityLog(object $share): void
    {
        $count = $this->countProducts($share->products_data);

        DB::table('enhanced_activity_logs')->insert([
            'user_id'        => $share->user_id ?: null,
            'business_id'    => $share->business_id ?: null,
            'action'         => 'create',
            'model_type'     => 'shared_product',
            'model_id'       => $share->id,
            'model_label'    => 'Shared ' . $count . ' product(s) via public link',
            'before_data'    => null,
            'after_data'     => json_encode([
                'token'      => $share->token,
                'expires_at' => (string) $share->expires_at,
            ]),
            'changed_fields' => json_encode(['token', 'expires_at']),
            'request_url'    => null,
            'request_method' => 'CLI/backfill',
            'ip_address'     => null,
            'user_agent'     => 'Artisan/backfill',
            'created_at'     => $share->created_at,
            'is_primary'     => 1,
        ]);
    }

    protected function countProducts($productsData): int
    {
        if (is_string($productsData)) {
            $productsData = json_decode($productsData, true);
        }
        return is_array($productsData) ? count($productsData) : 0;
    }
}
