<?php

namespace App\DataFixes;

use App\Models\RawMaterialPrice;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class FixRawMaterialMediaKeys extends BaseDataFix
{
    public function key(): string
    {
        return 'raw-material-media-keys';
    }

    public function description(): string
    {
        return 'Fix s3_key & buat media record untuk RawMaterialPrice';
    }

    public function fix(): array
    {
        $disk = Storage::disk('s3');
        $client = $disk->getClient();
        $bucket = config('filesystems.disks.s3.bucket');

        $this->info('Loading S3 file list...');
        $s3Files = [];
        $continuationToken = null;

        do {
            $params = [
                'Bucket' => $bucket,
                'Prefix' => 'raw-material/images/',
            ];
            if ($continuationToken) {
                $params['ContinuationToken'] = $continuationToken;
            }
            $result = $client->listObjectsV2($params);
            foreach ($result['Contents'] ?? [] as $obj) {
                $key = $obj['Key'];
                if (str_contains($key, '/conversions/')) {
                    continue;
                }
                if (preg_match('#raw-material/images/\d{4}-\d{2}-\d{2}/(\d+)/[^/]+$#', $key, $m)) {
                    $s3Files[(int) $m[1]] = $key;
                }
            }
            $continuationToken = $result['NextContinuationToken'] ?? null;
        } while ($continuationToken);

        $this->info('Found ' . count($s3Files) . ' files in S3.');

        // Build filename → s3_key map for matching
        $s3ByKey = [];
        foreach ($s3Files as $modelId => $s3Key) {
            $fileName = pathinfo($s3Key, PATHINFO_BASENAME);
            $s3ByKey[$modelId][$fileName] = $s3Key;
        }

        $allPrices = RawMaterialPrice::all(['id', 'variant']);

        $existingMediaAll = DB::table('media')
            ->where('model_type', 'App\\Models\\RawMaterialPrice')
            ->where('collection_name', 'images')
            ->get(['id', 'model_id', 'file_name', 'custom_properties']);

        $mediaByModel = [];
        foreach ($existingMediaAll as $m) {
            $props = json_decode($m->custom_properties, true);
            if (isset($props['module']) && $props['module'] === 'owner_verification_request') {
                continue;
            }
            $mediaByModel[$m->model_id][] = $m;
        }

        $fixed = 0;
        $fixedPath = 0;
        $skipped = 0;
        $noFile = 0;
        $details = [];

        foreach ($allPrices as $price) {
            if (isset($mediaByModel[$price->id])) {
                $allGood = true;

                foreach ($mediaByModel[$price->id] as $media) {
                    $currentKey = data_get(json_decode($media->custom_properties, true), 's3_key');

                    if ($currentKey && str_starts_with($currentKey, 'raw-material/images/')) {
                        continue;
                    }

                    // Match by filename first, fallback to model_id
                    $correctKey = null;
                    if (isset($s3ByKey[$price->id][$media->file_name])) {
                        $correctKey = $s3ByKey[$price->id][$media->file_name];
                    } elseif (isset($s3Files[$price->id])) {
                        $correctKey = $s3Files[$price->id];
                    }

                    if ($correctKey) {
                        DB::table('media')
                            ->where('id', $media->id)
                            ->update([
                                'custom_properties' => DB::raw("'".addslashes(json_encode(['s3_key' => $correctKey]))."'"),
                                'updated_at' => now(),
                            ]);

                        $details[] = [
                            'Price ID' => $price->id,
                            'Variant' => $price->variant,
                            'Action' => 'FIXED PATH',
                            'S3 Key' => $correctKey,
                        ];
                        $fixedPath++;
                        $allGood = false;
                    }
                }

                if ($allGood) {
                    $skipped++;
                }

                continue;
            }

            if (! isset($s3Files[$price->id])) {
                $noFile++;
                continue;
            }

            $s3Key = $s3Files[$price->id];
            $fileName = pathinfo($s3Key, PATHINFO_BASENAME);

            DB::table('media')->insert([
                'model_type'            => 'App\\Models\\RawMaterialPrice',
                'model_id'              => $price->id,
                'uuid'                  => Str::uuid()->toString(),
                'collection_name'       => 'images',
                'name'                  => pathinfo($s3Key, PATHINFO_FILENAME),
                'file_name'             => $fileName,
                'mime_type'             => 'image/jpeg',
                'disk'                  => 's3',
                'conversions_disk'      => 's3',
                'size'                  => 0,
                'manipulations'         => '[]',
                'custom_properties'     => json_encode(['s3_key' => $s3Key]),
                'generated_conversions' => '[]',
                'responsive_images'     => '[]',
                'order_column'          => 1,
                'created_at'            => now(),
                'updated_at'            => now(),
            ]);

            $details[] = [
                'Price ID' => $price->id,
                'Variant' => $price->variant,
                'Action' => 'CREATED',
                'S3 Key' => $s3Key,
            ];
            $fixed++;
        }

        if (! empty($details)) {
            $this->command->newLine();
            $this->command->table(['Price ID', 'Variant', 'Action', 'S3 Key'], $details);
        }

        $this->info("Created new media: {$fixed}");
        $this->info("Fixed s3_key path: {$fixedPath}");
        $this->info("Skipped (already correct): {$skipped}");
        $this->info("Skipped (no file in S3): {$noFile}");

        return [
            'fixed'   => $fixed + $fixedPath,
            'skipped' => $skipped,
            'total'   => $allPrices->count(),
        ];
    }
}
