<?php

namespace App\Livewire\Pricing;

use App\Domain\Identity\Models\Branch;
use App\Domain\Pricing\Enums\AdjustmentType;
use App\Domain\Pricing\Enums\PricingRuleType;
use App\Domain\Pricing\Models\PricingRule;
use App\Domain\Pricing\Support\ConditionSchema;
use App\Domain\Pricing\Support\Percent;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('قاعدة تسعير')]
class PricingRuleForm extends Component
{
    public ?PricingRule $pricingRule = null;
    public bool $editing = false;

    public string $name_ar = '';
    public string $name = '';
    public string $rule_type = '';
    public string $adjustment_type = '';
    public string $adjustment_value = '';
    public array $conditions = [];
    public string $target_type = '';
    public string $target_id = '';
    public string $branch_id = '';
    public int $priority = 0;
    public bool $is_stackable = true;
    public string $max_discount_percent = '';
    public string $effective_from = '';
    public string $effective_to = '';
    public bool $is_active = true;
    public string $usage_limit = '';

    public function mount(?PricingRule $pricingRule = null): void
    {
        $this->authorize('pricing.create');

        if ($pricingRule && $pricingRule->exists) {
            $this->authorize('pricing.update');
            $this->pricingRule = $pricingRule;
            $this->editing = true;
            $this->name_ar = $pricingRule->name_ar;
            $this->name = $pricingRule->name ?? '';
            $this->rule_type = $pricingRule->rule_type?->value ?? '';
            $this->adjustment_type = $pricingRule->adjustment_type?->value ?? '';
            $this->adjustment_value = $this->formatAdjustmentValueForDisplay($pricingRule);
            $this->conditions = $pricingRule->conditions ?? [];
            $this->target_type = $pricingRule->target_type ?? '';
            $this->target_id = (string) ($pricingRule->target_id ?? '');
            $this->branch_id = (string) ($pricingRule->branch_id ?? '');
            $this->priority = $pricingRule->priority ?? 0;
            $this->is_stackable = $pricingRule->is_stackable;
            $this->max_discount_percent = (string) ($pricingRule->max_discount_percent ?? '');
            $this->effective_from = $pricingRule->effective_from?->format('Y-m-d') ?? '';
            $this->effective_to = $pricingRule->effective_to?->format('Y-m-d') ?? '';
            $this->is_active = $pricingRule->is_active;
            $this->usage_limit = (string) ($pricingRule->usage_limit ?? '');
        } else {
            $this->effective_from = now()->format('Y-m-d');
        }
    }

    private function formatAdjustmentValueForDisplay(PricingRule $rule): string
    {
        if (in_array($rule->adjustment_type, [AdjustmentType::FixedDiscount, AdjustmentType::FixedPrice])) {
            return (string) ($rule->adjustment_value / 100);
        }

        // Percentages live in the column as basis points; humans read percent.
        return (string) Percent::fromBasisPoints((int) $rule->adjustment_value);
    }

    public function rules(): array
    {
        return [
            'name_ar' => 'required|string|max:255',
            'name' => 'nullable|string|max:255',
            'rule_type' => 'required|in:' . implode(',', array_column(PricingRuleType::cases(), 'value')),
            'adjustment_type' => 'required|in:' . implode(',', array_column(AdjustmentType::cases(), 'value')),
            'adjustment_value' => 'required|numeric|min:0.01',
            'conditions' => 'nullable|array',
            'target_type' => 'nullable|string|max:255',
            'target_id' => 'nullable|integer',
            'branch_id' => 'nullable|integer|exists:branches,id',
            'priority' => 'integer|min:0',
            'is_stackable' => 'boolean',
            'max_discount_percent' => 'nullable|integer|min:1|max:100',
            'effective_from' => 'required|date',
            'effective_to' => 'nullable|date|after:effective_from',
            'is_active' => 'boolean',
            'usage_limit' => 'nullable|integer|min:1',
        ];
    }

    public function messages(): array
    {
        return [
            'name_ar.required' => __('الاسم بالعربية مطلوب'),
            'rule_type.required' => __('نوع القاعدة مطلوب'),
            'rule_type.in' => __('نوع القاعدة غير صالح'),
            'adjustment_type.required' => __('نوع التعديل مطلوب'),
            'adjustment_type.in' => __('نوع التعديل غير صالح'),
            'adjustment_value.required' => __('قيمة التعديل مطلوبة'),
            'adjustment_value.min' => __('قيمة التعديل يجب أن تكون أكبر من صفر'),
            'effective_from.required' => __('تاريخ البداية مطلوب'),
            'effective_to.after' => __('تاريخ النهاية يجب أن يكون بعد تاريخ البداية'),
            'max_discount_percent.min' => __('الحد الأقصى للخصم يجب أن يكون بين 1 و 100'),
            'max_discount_percent.max' => __('الحد الأقصى للخصم يجب أن يكون بين 1 و 100'),
        ];
    }

    public function updatedRuleType(): void
    {
        $this->conditions = [];
    }

    public function save(): void
    {
        $this->validate();

        $adjustmentValue = $this->computeAdjustmentValueForStorage();

        // Every write goes through the schema so condition keys cannot drift
        // away from what the engine reads.
        $conditions = ConditionSchema::normalize($this->rule_type, $this->conditions ?? []);

        if (! ConditionSchema::isMeaningful($this->rule_type, $conditions)) {
            $this->addError('conditions', __('يجب تحديد شرط واحد على الأقل — وإلا سيُطبق الخصم على الجميع'));

            return;
        }

        $data = [
            'name_ar' => $this->name_ar,
            'name' => $this->name ?: null,
            'rule_type' => $this->rule_type,
            'adjustment_type' => $this->adjustment_type,
            'adjustment_value' => $adjustmentValue,
            'conditions' => $conditions,
            'target_type' => $this->target_type ?: null,
            'target_id' => $this->target_id ? (int) $this->target_id : null,
            'branch_id' => $this->branch_id ? (int) $this->branch_id : null,
            'priority' => $this->priority,
            'is_stackable' => $this->is_stackable,
            'max_discount_percent' => $this->max_discount_percent ? (int) $this->max_discount_percent : null,
            'effective_from' => $this->effective_from,
            'effective_to' => $this->effective_to ?: null,
            'is_active' => $this->is_active,
            'usage_limit' => $this->usage_limit ? (int) $this->usage_limit : null,
        ];

        if ($this->editing && $this->pricingRule) {
            $this->pricingRule->update($data);
            session()->flash('success', __('تم تحديث القاعدة بنجاح'));
        } else {
            $data['created_by'] = auth()->id();
            $data['usage_count'] = 0;
            PricingRule::create($data);
            session()->flash('success', __('تم إنشاء القاعدة بنجاح'));
        }

        $this->redirect(route('pricing.rules'), navigate: true);
    }

    private function computeAdjustmentValueForStorage(): int
    {
        $type = AdjustmentType::tryFrom($this->adjustment_type);
        if (in_array($type, [AdjustmentType::FixedDiscount, AdjustmentType::FixedPrice])) {
            return (int) round((float) $this->adjustment_value * 100);
        }

        // The engine divides by 10000. Storing a bare "20" made every
        // percentage discount 100x too small.
        return Percent::toBasisPoints($this->adjustment_value);
    }

    public function render()
    {
        return view('livewire.pricing.pricing-rule-form', [
            'branches' => Branch::orderBy('name_ar')->get(),
            'ruleTypes' => collect(PricingRuleType::cases())->mapWithKeys(fn ($t) => [$t->value => $t->label()])->toArray(),
            'adjustmentTypes' => collect(AdjustmentType::cases())->mapWithKeys(fn ($t) => [$t->value => $t->label()])->toArray(),
        ]);
    }
}
