<?php

namespace App\Services\Admin\ProductConfigOptionGroup;

use App\Models\Admin;
use App\Models\Log;
use App\Models\Pricing;
use App\Models\ProductConfigOption;
use App\Models\ProductConfigOptionGroup;
use App\Models\ProductConfigOptionValue;
use Illuminate\Support\Facades\DB;

class DuplicateGroupService
{
    public function execute(
        ProductConfigOptionGroup $source,
        Admin $admin,
        ?string $ipAddress = null,
    ): ProductConfigOptionGroup {
        if ($source->isArchived()) {
            throw new \DomainException('source_archived');
        }

        return DB::transaction(function () use ($source, $admin, $ipAddress) {
            $prefix = trans('admin/product-config-option-groups.duplicate_prefix');
            // Fallback if translation key not yet defined
            if ($prefix === 'admin/product-config-option-groups.duplicate_prefix') {
                $prefix = '[KOPYA]';
            }
            $maxOrder = ProductConfigOptionGroup::max('order') ?? 0;

            $clone = ProductConfigOptionGroup::create([
                'name' => trim($prefix.' '.$source->name),
                'description' => $source->description,
                'hidden' => $source->hidden ?? false,
                'order' => $maxOrder + 1,
            ]);

            $clonedCount = 0;

            // Use direct query to bypass configOptions() scope that filters hidden=false
            $sourceOptions = ProductConfigOption::where('group_id', $source->id)
                ->whereNull('archived_at')
                ->get();

            foreach ($sourceOptions as $option) {
                $newOption = ProductConfigOption::create([
                    'group_id' => $clone->id,
                    'name' => $option->name,
                    'description' => $option->description,
                    'type' => $option->type,
                    'minimum' => $option->minimum,
                    'maximum' => $option->maximum,
                    'values' => $option->values ?? [],
                    'order' => $option->order,
                    'hidden' => $option->hidden,
                    'is_required' => $option->is_required,
                ]);
                $clonedCount++;

                foreach (ProductConfigOptionValue::where('option_id', $option->id)->get() as $val) {
                    ProductConfigOptionValue::create([
                        'option_id' => $newOption->id,
                        'value' => $val->value,
                        'order' => $val->order,
                        'status' => $val->status,
                    ]);
                }

                foreach (Pricing::where('type', 'product_config')->where('relation_id', $option->id)->get() as $pr) {
                    Pricing::create([
                        'type' => 'product_config',
                        'relation_id' => $newOption->id,
                        'currency_id' => $pr->currency_id,
                        'period' => $pr->period,
                        'time' => $pr->time,
                        'segment' => $pr->segment,
                        'amount' => $pr->amount,
                        'setup_amount' => $pr->setup_amount,
                        'order' => $pr->order,
                    ]);
                }
            }

            // NOTE: Canonical pattern is "log BEFORE mutation" (see ArchiveGroupService).
            // For Duplicate we log AFTER the cascade because the description references
            // $clone->id and $clonedCount — values that only exist after the cascade runs.
            // The DB::transaction still ensures atomicity: if anything fails, both the
            // cascade inserts AND this log record are rolled back together.
            Log::create([
                'type' => Log::TYPE_ADMIN,
                'observer' => $admin->name,
                'module' => 'ProductConfigOptionGroup',
                'method' => 'duplicated',
                'admin_id' => $admin->id,
                'ip_address' => $ipAddress ?? '0.0.0.0',
                'description' => "Duplicated option group #{$source->id} -> #{$clone->id} ({$clonedCount} options cloned)",
                'request' => ['source_id' => $source->id, 'clone_id' => $clone->id, 'options_count' => $clonedCount],
            ]);

            return $clone;
        });
    }
}
