<?php

namespace App\Livewire\Forms\Studio\Loyalty;

use App\Enums\IsShow;
use App\Enums\VoucherType;
use App\Models\Voucher;
use App\Rules\UnsignedInteger;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Livewire\Form;

class VoucherForm extends Form
{
    public ?Voucher $voucher = null;

    public string $name = '';

    public string $code = '';

    public string $tags = '';

    public string $type = '1';

    public string $discount_amount = '';

    public ?string $min_purchase = null;

    public ?string $max_discount = null;

    public ?string $quota = null;

    public string $limit_per_user = '';

    public string $summary = '';

    public string $start_date = '';

    public ?string $end_date = null;

    public array $tier_ids = [];

    public array $outlet_ids = [];

    public int $is_show = 1;

    public function rules(): array
    {
        return [
            'name' => ['required', 'string', 'max:50'],
            'code' => [
                'required',
                'string',
                'max:20',
                'alpha_num',
                Rule::unique('vouchers', 'code')->ignore($this->voucher),
            ],
            'tags' => ['required', 'string', 'max:20'],
            'type' => ['required', Rule::in(VoucherType::values())],
            'discount_amount' => [
                'required',
                Rule::when(
                    fn () => $this->type == VoucherType::PERCENTAGE->value,
                    ['integer', 'between:0,100'],
                    [new UnsignedInteger],
                ),
            ],
            'min_purchase' => ['nullable', new UnsignedInteger],
            'max_discount' => [
                Rule::when(
                    fn () => $this->type == VoucherType::PERCENTAGE->value,
                    ['required', new UnsignedInteger],
                    ['nullable'],
                ),
            ],
            'quota' => ['nullable', new UnsignedInteger],
            'limit_per_user' => ['required', new UnsignedInteger],
            'summary' => ['required', 'string', 'max:200'],
            'start_date' => ['required', 'date',  Rule::when(
                $this->voucher && $this->start_date !== $this->voucher->start_date,
                'after_or_equal:today'
            )],
            'end_date' => ['nullable', 'date', 'after_or_equal:start_date'],
            'tier_ids' => ['required', 'array', 'min:1'],
            'tier_ids.*' => Rule::exists('tiers', 'id'),
            'outlet_ids' => ['required', 'array', 'min:1'],
            'outlet_ids.*' => Rule::exists('outlets', 'id'),
            'is_show' => ['required', Rule::in(IsShow::values())],
        ];
    }

    public function validationAttributes(): array
    {
        return [
            'name' => 'nama',
            'code' => 'kode',
            'min_purchase' => 'min. belanja',
            'max_discount' => 'maks. diskon',
            'quota' => 'kuota',
            'limit_per_user' => 'limit per user',
            'summary' => 'summary',
            'type' => 'Tipe',
            'discount_amount' => 'Jumlah Diskon',
            'start_date' => 'tanggal mulai',
            'end_date' => 'tanggal selesai',
            'tier_ids' => 'tier',
            'tier_ids.*' => 'tier',
            'outlet_ids' => 'outlet',
            'outlet_ids.*' => 'outlet',
            'is_show' => 'visibilitas',
        ];
    }

    public function setVoucher(Voucher $voucher): void
    {
        $voucher->load(['outlets', 'tiers']);

        $this->voucher = $voucher;

        $this->name = $this->voucher->name;
        $this->code = $this->voucher->code;
        $this->tags = $this->voucher->tags;
        $this->type = $this->voucher->type->value;
        $this->discount_amount = parseRupiahToInt($this->voucher->discount_amount);
        $this->min_purchase = parseRupiahToInt($this->voucher->min_purchase);
        $this->max_discount = parseRupiahToInt($this->voucher->max_discount);
        $this->quota = $this->voucher->quota;
        $this->limit_per_user = $this->voucher->limit_per_user;
        $this->summary = $this->voucher->summary;
        $this->start_date = $this->voucher->start_date;
        $this->end_date = $this->voucher->end_date;
        $this->is_show = $this->voucher->is_show->value;

        $this->tier_ids = $this->voucher->tiers->pluck('id')->toArray();

        $this->outlet_ids = $this->voucher->outlets->pluck('id')->toArray();
    }

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

        $data = $this->prepareSavedData();

        foreach (['min_purchase', 'max_discount', 'quota', 'limit_per_user'] as $key) {
            if ($data[$key] === '') {
                $data[$key] = null;
            }
        }

        DB::transaction(function () use ($data) {
            $voucher = Voucher::create($data);

            $voucher->outlets()->attach($this->outlet_ids);
            $voucher->tiers()->attach($this->tier_ids);
        });
    }

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

        $data = $this->prepareSavedData();

        DB::transaction(function () use ($data) {
            unset($data['available_count']);
            $this->voucher->update($data);

            $this->voucher->outlets()->sync($this->outlet_ids);
            $this->voucher->tiers()->sync($this->tier_ids);
        });
    }

    private function prepareSavedData(): array
    {
        return [
            'name' => $this->name,
            'code' => $this->code,
            'tags' => $this->tags,
            'type' => $this->type,
            'discount_amount' => parseRupiahToInt($this->discount_amount),
            'min_purchase' => parseRupiahToInt($this->min_purchase),
            'max_discount' => $this->type == VoucherType::PERCENTAGE->value ? parseRupiahToInt($this->max_discount) : null,
            'quota' => parseRupiahToInt($this->quota),
            'available_count' => empty($this->quota) ? 0 : parseRupiahToInt($this->quota),
            'limit_per_user' => parseRupiahToInt($this->limit_per_user),
            'summary' => $this->summary,
            'start_date' => $this->start_date,
            'end_date' => $this->end_date,
            'is_show' => $this->is_show,
        ];
    }
}
