<?php

namespace App\Livewire\Inventory;

use App\Domain\Inventory\Enums\ProductType;
use App\Domain\Inventory\Models\Product;
use App\Domain\Inventory\Models\ProductCategory;
use App\Domain\Inventory\Models\ProductInstallmentPlan;
use App\Domain\Shared\Exceptions\DomainException;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('المنتجات')]
class ProductForm extends Component
{
    public ?Product $product = null;
    public bool $editing = false;

    public string $name_ar = '';
    public string $name = '';
    public string $sku = '';
    public string $barcode = '';
    public ?int $category_id = null;
    public string $type = 'physical';
    public string $selling_price = '';
    public string $cost_price = '';
    public bool $track_inventory = true;
    public ?int $min_stock_level = null;
    public ?int $max_stock_level = null;
    public string $tax_rate = '0';
    public bool $is_active = true;
    public bool $is_essential = false;
    public string $description_ar = '';

    // Annual billing
    public string $billing_cycle = 'one_time';
    public string $member_price = '';
    public string $non_member_price = '';

    // Installment plan rows  [['tier','label_ar','installments','frequency','down_payment_pct']]
    public array $planRows = [];

    public function mount(?Product $product = null): void
    {
        $this->authorize('inventory.create');

        if ($product && $product->exists) {
            $this->authorize('inventory.update');
            $this->product = $product;
            $this->editing = true;

            $this->name_ar        = $product->name_ar ?? '';
            $this->name           = $product->name ?? '';
            $this->sku            = $product->sku ?? '';
            $this->barcode        = $product->barcode ?? '';
            $this->category_id    = $product->category_id;
            $this->type           = $product->type->value ?? 'physical';
            $this->selling_price  = $product->selling_price ? (string) ($product->selling_price / 100) : '';
            $this->cost_price     = $product->cost_price ? (string) ($product->cost_price / 100) : '';
            $this->track_inventory = $product->track_inventory;
            $this->min_stock_level = $product->min_stock_level;
            $this->max_stock_level = $product->max_stock_level;
            $this->tax_rate       = (string) ($product->tax_rate ?? 0);
            $this->is_active      = $product->is_active;
            $this->is_essential   = $product->is_essential ?? false;
            $this->description_ar = $product->description_ar ?? '';
            $this->billing_cycle  = $product->billing_cycle ?? 'one_time';
            $this->member_price   = $product->member_price ? (string) ($product->member_price / 100) : '';
            $this->non_member_price = $product->non_member_price ? (string) ($product->non_member_price / 100) : '';

            $this->planRows = $product->installmentPlans()
                ->orderBy('sort_order')
                ->get()
                ->map(fn ($p) => [
                    'id'                  => $p->id,
                    'tier'                => $p->membership_tier,
                    'label_ar'            => $p->label_ar,
                    'installments'        => (string) $p->installments,
                    'frequency'           => $p->frequency,
                    'down_payment_pct'    => (string) $p->down_payment_pct,
                    'installment_amounts' => $this->buildAmountsArray($p->installment_amounts, $p->installments),
                    'is_active'           => $p->is_active,
                ])
                ->toArray();
        }
    }

    public function addPlanRow(): void
    {
        $this->planRows[] = [
            'id'                  => null,
            'tier'                => 'any',
            'label_ar'            => '',
            'installments'        => '3',
            'frequency'           => 'monthly',
            'down_payment_pct'    => '0',
            'installment_amounts' => [],   // array indexed by slot: '' means auto
            'is_active'           => true,
        ];
    }

    public function syncInstallmentSlots(int $rowIndex): void
    {
        $count = (int) ($this->planRows[$rowIndex]['installments'] ?? 3);
        $current = $this->planRows[$rowIndex]['installment_amounts'] ?? [];
        $this->planRows[$rowIndex]['installment_amounts'] = $this->buildAmountsArray($current, $count);
    }

    private function buildAmountsArray(?array $stored, int $count): array
    {
        $out = [];
        for ($i = 0; $i < $count; $i++) {
            $v = $stored[$i] ?? null;
            // Store as pounds string for the form; '' means auto
            $out[$i] = ($v !== null && $v > 0) ? (string) ($v / 100) : '';
        }
        return $out;
    }

    public function removePlanRow(int $index): void
    {
        array_splice($this->planRows, $index, 1);
    }

    public function rules(): array
    {
        $uniqueSku = $this->editing
            ? 'unique:products,sku,' . $this->product->id
            : 'unique:products,sku';

        $rules = [
            'name_ar'          => 'required|string|max:255',
            'name'             => 'nullable|string|max:255',
            'sku'              => ['nullable', 'string', 'max:50', $uniqueSku],
            'barcode'          => 'nullable|string|max:50',
            'category_id'      => 'nullable|exists:product_categories,id',
            'type'             => 'required|in:physical,digital,service',
            'selling_price'    => 'required|numeric|min:0',
            'cost_price'       => 'nullable|numeric|min:0',
            'track_inventory'  => 'boolean',
            'min_stock_level'  => 'nullable|integer|min:0',
            'max_stock_level'  => 'nullable|integer|min:0',
            'tax_rate'         => 'nullable|numeric|min:0|max:100',
            'is_active'        => 'boolean',
            'is_essential'     => 'boolean',
            'description_ar'   => 'nullable|string|max:1000',
            'billing_cycle'    => 'required|in:one_time,annual',
            'member_price'     => 'nullable|numeric|min:0',
            'non_member_price' => 'nullable|numeric|min:0',
        ];

        foreach ($this->planRows as $i => $row) {
            $rules["planRows.{$i}.tier"]             = 'required|in:member,non_member,any';
            $rules["planRows.{$i}.label_ar"]         = 'required|string|max:100';
            $rules["planRows.{$i}.installments"]     = 'required|integer|min:2|max:24';
            $rules["planRows.{$i}.frequency"]        = 'required|in:weekly,biweekly,monthly,quarterly';
            $rules["planRows.{$i}.down_payment_pct"] = 'required|integer|min:0|max:100';
        }

        return $rules;
    }

    public function messages(): array
    {
        return [
            'name_ar.required'         => 'اسم المنتج بالعربية مطلوب',
            'sku.unique'               => 'رمز المنتج مستخدم بالفعل',
            'type.required'            => 'نوع المنتج مطلوب',
            'selling_price.required'   => 'السعر الأساسي مطلوب',
            'selling_price.min'        => 'السعر يجب ألا يكون سالبًا',
            'billing_cycle.required'   => 'دورة الفوترة مطلوبة',
            'planRows.*.label_ar.required'     => 'اسم الخطة مطلوب',
            'planRows.*.installments.required' => 'عدد الأقساط مطلوب',
            'planRows.*.installments.min'      => 'يجب أن يكون عدد الأقساط 2 على الأقل',
        ];
    }

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

        try {
            $data = [
                'name_ar'          => $this->name_ar,
                'name'             => $this->name ?: null,
                'sku'              => $this->sku ?: $this->generateSku(),
                'barcode'          => $this->barcode ?: null,
                'category_id'      => $this->category_id,
                'type'             => $this->type,
                'selling_price'    => (int) round((float) $this->selling_price * 100),
                'cost_price'       => $this->cost_price ? (int) round((float) $this->cost_price * 100) : null,
                'track_inventory'  => $this->track_inventory,
                'min_stock_level'  => $this->min_stock_level,
                'max_stock_level'  => $this->max_stock_level,
                'tax_rate'         => (int) $this->tax_rate,
                'is_active'        => $this->is_active,
                'is_essential'     => $this->is_essential,
                'description_ar'   => $this->description_ar ?: null,
                'billing_cycle'    => $this->billing_cycle,
                'member_price'     => $this->member_price !== '' ? (int) round((float) $this->member_price * 100) : null,
                'non_member_price' => $this->non_member_price !== '' ? (int) round((float) $this->non_member_price * 100) : null,
            ];

            if ($this->editing) {
                $this->product->update($data);
                $product = $this->product;
                session()->flash('success', __('تم تحديث المنتج بنجاح'));
            } else {
                $data['created_by'] = auth()->id();
                $data['branch_id']  = session('active_branch_id');
                $product = Product::create($data);
                session()->flash('success', __('تم إنشاء المنتج بنجاح'));
            }

            // Sync installment plan rows
            $this->syncPlanRows($product);

            $this->redirect(route('inventory.products'), navigate: true);
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        } catch (\Illuminate\Database\QueryException $e) {
            if (str_contains($e->getMessage(), 'unique')) {
                session()->flash('error', __('رمز المنتج (SKU) مستخدم بالفعل'));
            } else {
                session()->flash('error', __('حدث خطأ أثناء حفظ المنتج'));
            }
        }
    }

    private function syncPlanRows(Product $product): void
    {
        $keepIds = [];

        foreach ($this->planRows as $i => $row) {
            // Convert amounts from pounds strings to piaster integers (null for blanks)
            $amounts = [];
            foreach ($row['installment_amounts'] ?? [] as $idx => $val) {
                $amounts[$idx] = ($val !== '' && $val !== null)
                    ? (int) round((float) $val * 100)
                    : null;
            }
            // If all nulls, store null instead of an array
            $hasExplicit = array_filter($amounts, fn ($v) => $v !== null);
            $installmentAmounts = $hasExplicit ? $amounts : null;

            $planData = [
                'academy_id'          => $product->academy_id,
                'product_id'          => $product->id,
                'membership_tier'     => $row['tier'],
                'label_ar'            => $row['label_ar'],
                'installments'        => (int) $row['installments'],
                'frequency'           => $row['frequency'],
                'down_payment_pct'    => (int) $row['down_payment_pct'],
                'installment_amounts' => $installmentAmounts,
                'is_active'           => $row['is_active'] ?? true,
                'sort_order'          => $i,
            ];

            if (!empty($row['id'])) {
                $plan = ProductInstallmentPlan::find($row['id']);
                if ($plan) {
                    $plan->update($planData);
                    $keepIds[] = $plan->id;
                }
            } else {
                $plan = ProductInstallmentPlan::create($planData);
                $keepIds[] = $plan->id;
            }
        }

        // Delete removed rows
        $product->installmentPlans()
            ->when(!empty($keepIds), fn ($q) => $q->whereNotIn('id', $keepIds))
            ->delete();
    }

    private function generateSku(): string
    {
        $prefix = match ($this->type) {
            'service' => 'SRV',
            'digital' => 'DIG',
            default   => 'PRD',
        };
        $count = Product::withoutGlobalScopes()->count() + 1;
        return $prefix . '-' . str_pad($count, 4, '0', STR_PAD_LEFT);
    }

    public function render()
    {
        return view('livewire.inventory.product-form', [
            'categories' => ProductCategory::active()->orderBy('name_ar')->get(['id', 'name_ar']),
            'typeOptions' => [
                'physical' => 'منتج مادي',
                'digital'  => 'منتج رقمي',
                'service'  => 'خدمة',
            ],
        ]);
    }
}
