<?php

namespace App\Modules\Customization\CustomFields\Services;

use App\Modules\Admin\Tenancy\Models\Tenant;
use App\Modules\Admin\Tenancy\Services\CustomFieldsPlanService;
use App\Modules\Admin\Tenancy\Services\PlanLimitEnforcementService;
use App\Modules\Admin\Tenancy\Support\PlanLimitKeys;
use App\Modules\Customization\CustomFields\DTOs\CustomFieldWriteData;
use App\Modules\Customization\CustomFields\Models\CustomField;
use App\Modules\Customization\CustomFields\Repositories\CustomFieldRepository;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class CustomFieldService
{
    public function __construct(
        private readonly CustomFieldRepository $fields,
        private readonly CustomFieldsPlanService $plan,
        private readonly PlanLimitEnforcementService $planLimits,
    ) {}

    public function listForTenant(int $tenantId, string $module, string $entity): \Illuminate\Database\Eloquent\Collection
    {
        return CustomField::query()
            ->where('tenant_id', $tenantId)
            ->where('module', $module)
            ->where('entity', $entity)
            ->with('options')
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get();
    }

    public function store(Tenant $tenant, CustomFieldWriteData $data): CustomField
    {
        if (! $this->plan->isEnabledForTenant($tenant)) {
            throw ValidationException::withMessages([
                'name' => [__('custom_fields.validation.feature_disabled')],
            ]);
        }
        $this->planLimits->assertCanIncrement($tenant, PlanLimitKeys::CUSTOM_FIELDS_LIMIT);

        $field = DB::transaction(function () use ($tenant, $data): CustomField {
            $next = (int) CustomField::query()
                ->where('tenant_id', $tenant->id)
                ->where('module', $data->module)
                ->where('entity', $data->entity)
                ->max('sort_order') + 1;

            $created = $this->fields->create($data->toFieldArray((int) $tenant->id, auth()->id(), $next));
            $this->syncOptions($created, $data->options);
            $this->fields->forgetDefinitionsCache((int) $tenant->id, $data->module, $data->entity);

            return $created->fresh('options');
        });

        $this->planLimits->evaluateAfterIncrement($tenant, PlanLimitKeys::CUSTOM_FIELDS_LIMIT);

        return $field;
    }

    public function update(CustomField $field, CustomFieldWriteData $data): CustomField
    {
        return DB::transaction(function () use ($field, $data): CustomField {
            $payload = [
                'name' => $data->name,
                'slug' => $data->slug,
                'field_type' => $data->fieldType,
                'is_required' => $data->isRequired,
                'is_active' => $data->isActive,
                'validation_rules' => $data->validationRules,
                'placeholder' => $data->placeholder,
                'help_text' => $data->helpText,
                'updated_by' => auth()->id(),
            ];
            if ($data->sortOrder !== null) {
                $payload['sort_order'] = $data->sortOrder;
            }
            $updated = $this->fields->update($field, $payload);
            $field->options()->delete();
            $this->syncOptions($updated, $data->options);
            $this->fields->forgetDefinitionsCache((int) $field->tenant_id, $field->module, $field->entity);

            return $updated->fresh('options');
        });
    }

    public function deactivate(CustomField $field): void
    {
        $this->fields->update($field, ['is_active' => false, 'updated_by' => auth()->id()]);
        $this->fields->forgetDefinitionsCache((int) $field->tenant_id, $field->module, $field->entity);
    }

    /**
     * @param  list<array{label: string, value: string}>  $options
     */
    private function syncOptions(CustomField $field, array $options): void
    {
        $pos = 0;
        foreach ($options as $opt) {
            $field->options()->create([
                'label' => $opt['label'],
                'value' => $opt['value'],
                'sort_order' => $pos,
            ]);
            $pos++;
        }
    }
}
