<?php

namespace App\Livewire\Pricing;

use App\Domain\Identity\Models\Branch;
use App\Domain\Pricing\Enums\AdjustmentType;
use App\Domain\Pricing\Enums\PromotionType;
use App\Domain\Pricing\Models\Promotion;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('عرض / كوبون')]
class PromotionForm extends Component
{
    public ?Promotion $promotion = null;
    public bool $editing = false;

    public string $name_ar = '';
    public string $name = '';
    public string $code = '';
    public string $type = '';
    public string $adjustment_type = '';
    public string $adjustment_value = '';
    public string $target_type = '';
    public string $target_id = '';
    public string $branch_id = '';
    public string $min_purchase_amount = '';
    public string $max_discount_amount = '';
    public string $start_date = '';
    public string $end_date = '';
    public bool $is_active = true;
    public string $usage_limit = '';
    public string $per_participant_limit = '';
    public int $priority = 0;

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

        if ($promotion && $promotion->exists) {
            $this->authorize('pricing.update');
            $this->promotion = $promotion;
            $this->editing = true;
            $this->name_ar = $promotion->name_ar;
            $this->name = $promotion->name ?? '';
            $this->code = $promotion->code ?? '';
            $this->type = $promotion->type?->value ?? '';
            $this->adjustment_type = $promotion->adjustment_type?->value ?? '';
            $this->adjustment_value = $this->formatAdjustmentForDisplay($promotion);
            $this->target_type = $promotion->target_type ?? '';
            $this->target_id = (string) ($promotion->target_id ?? '');
            $this->branch_id = (string) ($promotion->branch_id ?? '');
            $this->min_purchase_amount = $promotion->min_purchase_amount ? (string) ($promotion->min_purchase_amount / 100) : '';
            $this->max_discount_amount = $promotion->max_discount_amount ? (string) ($promotion->max_discount_amount / 100) : '';
            $this->start_date = $promotion->start_date?->format('Y-m-d') ?? '';
            $this->end_date = $promotion->end_date?->format('Y-m-d') ?? '';
            $this->is_active = $promotion->is_active;
            $this->usage_limit = (string) ($promotion->usage_limit ?? '');
            $this->per_participant_limit = (string) ($promotion->per_participant_limit ?? '');
            $this->priority = $promotion->priority ?? 0;
        } else {
            $this->start_date = now()->format('Y-m-d');
        }
    }

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

        return (string) \App\Domain\Pricing\Support\Percent::fromBasisPoints((int) $promotion->adjustment_value);
    }

    public function rules(): array
    {
        return [
            'name_ar' => 'required|string|max:255',
            'name' => 'nullable|string|max:255',
            'code' => $this->type === 'coupon' ? 'required|string|max:50' : 'nullable|string|max:50',
            'type' => 'required|in:' . implode(',', array_column(PromotionType::cases(), 'value')),
            'adjustment_type' => 'required|in:' . implode(',', array_column(AdjustmentType::cases(), 'value')),
            'adjustment_value' => 'required|numeric|min:0.01',
            'target_type' => 'nullable|string|max:255',
            'target_id' => 'nullable|integer',
            'branch_id' => 'nullable|integer|exists:branches,id',
            'min_purchase_amount' => 'nullable|numeric|min:0',
            'max_discount_amount' => 'nullable|numeric|min:0',
            'start_date' => 'required|date',
            'end_date' => 'nullable|date|after:start_date',
            'is_active' => 'boolean',
            'usage_limit' => 'nullable|integer|min:1',
            'per_participant_limit' => 'nullable|integer|min:1',
            'priority' => 'integer|min:0',
        ];
    }

    public function messages(): array
    {
        return [
            'name_ar.required' => __('الاسم بالعربية مطلوب'),
            'code.required' => __('كود الكوبون مطلوب'),
            'type.required' => __('نوع العرض مطلوب'),
            'type.in' => __('نوع العرض غير صالح'),
            'adjustment_type.required' => __('نوع التعديل مطلوب'),
            'adjustment_type.in' => __('نوع التعديل غير صالح'),
            'adjustment_value.required' => __('قيمة التعديل مطلوبة'),
            'adjustment_value.min' => __('قيمة التعديل يجب أن تكون أكبر من صفر'),
            'start_date.required' => __('تاريخ البداية مطلوب'),
            'end_date.after' => __('تاريخ النهاية يجب أن يكون بعد تاريخ البداية'),
        ];
    }

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

        $adjustmentValue = $this->computeAdjustmentValueForStorage();

        $data = [
            'name_ar' => $this->name_ar,
            'name' => $this->name ?: null,
            'code' => ($this->type === 'coupon' && $this->code) ? strtoupper($this->code) : null,
            'type' => $this->type,
            'adjustment_type' => $this->adjustment_type,
            'adjustment_value' => $adjustmentValue,
            '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,
            'min_purchase_amount' => $this->min_purchase_amount ? (int) round((float) $this->min_purchase_amount * 100) : null,
            'max_discount_amount' => $this->max_discount_amount ? (int) round((float) $this->max_discount_amount * 100) : null,
            'start_date' => $this->start_date,
            'end_date' => $this->end_date ?: null,
            'is_active' => $this->is_active,
            'usage_limit' => $this->usage_limit ? (int) $this->usage_limit : null,
            'per_participant_limit' => $this->per_participant_limit ? (int) $this->per_participant_limit : null,
            'priority' => $this->priority,
        ];

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

        $this->redirect(route('pricing.promotions'), 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);
        }

        // Basis points — the engine divides by 10000.
        return \App\Domain\Pricing\Support\Percent::toBasisPoints($this->adjustment_value);
    }

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