<?php

namespace App\Livewire\Forms\Studio\Master;

use App\Enums\Day;
use App\Enums\OutletStatus;
use App\Models\OpeningHour;
use App\Models\Outlet;
use App\Rules\PhoneNumber;
use App\Traits\WithMediaHandler;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Livewire\Form;

class OutletForm extends Form
{
    use WithMediaHandler;

    public ?Outlet $outlet = null;

    public string $name = '';

    public string $phone_number = '';

    public string $address = '';

    public ?string $landmark = null;

    public ?string $maps_url = null;

    public array $opening_hours = [];

    public array $facilities = ['Parkir'];

    public string $opened_date = '';

    public string $status = '1';

    public array $featured_image = [];

    public array $images = [];

    public function rules(): array
    {
        $rules = [
            'name' => ['required', 'string', 'max:100'],
            'phone_number' => ['required', 'string', new PhoneNumber],
            'address' => ['required', 'string'],
            'landmark' => ['required', 'string', 'max:30'],
            'maps_url' => [
                'nullable',
                'string',
                'regex:/^(https?:\/\/)?(www\.)?(google\.[a-z.]+\/maps\/.+|goo\.gl\/maps\/.+|maps\.app\.goo\.gl\/.+)$/i',
            ],
            'opening_hours' => ['required', 'array'],
            'facilities' => ['required', 'array', 'min:1'],
            'facilities.*' => ['required', 'string', 'max:20'],
            'opened_date' => ['required', 'date'],
            'status' => ['required', Rule::in(OutletStatus::cases())],
            'featured_image' => ['required', 'array', 'max:1'],
            'images' => ['required', 'array', 'max:5'],
        ];

        foreach (Day::cases() as $day) {
            $rules["opening_hours.{$day->value}"] = ['required', 'array'];
            $rules["opening_hours.{$day->value}.open_time"] = ['nullable', 'date_format:H:i'];
            $rules["opening_hours.{$day->value}.close_time"] = ['nullable', 'date_format:H:i'];
        }

        return $rules;
    }

    public function validationAttributes(): array
    {
        return [
            'name' => 'nama',
            'phone_number' => 'nomor telepon',
            'address' => 'alamat',
            'landmark' => 'patokan',
            'maps_url' => 'tautan google maps',
            'opening_hours' => 'jam beroperasi',
            'opening_hours.*' => 'jam beroperasi',
            'facilities' => 'fasilitas',
            'facilities.*' => 'fasilitas',
            'opened_date' => 'tanggal buka',
            'featured_image' => 'gambar utama',
            'images' => 'gambar',
        ];
    }

    public function setOutlet(Outlet $outlet)
    {
        $outlet = $outlet->load(['openingHours', 'facilities']);

        $this->outlet = $outlet;

        $this->name = $outlet->name;
        $this->phone_number = $outlet->phone_number;
        $this->address = $outlet->address;
        $this->landmark = $outlet->landmark;
        $this->maps_url = $outlet->maps_url;
        $this->opening_hours = $outlet->openingHours
            ->mapWithKeys(fn ($item) => [
                $item->day->value => [
                    'open_time' => $item->open_time ? formatTime($item->open_time) : null,
                    'close_time' => $item->close_time ? formatTime($item->close_time) : null,
                ],
            ])
            ->toArray();
        $this->facilities = $outlet->facilities->pluck('name')->toArray();
        $this->opened_date = $outlet->opened_date;
        $this->status = $outlet->status->value;
        $this->featured_image = $this->mapMediaCollection($outlet->getMedia('featured_image'));
        $this->images = $this->mapMediaCollection($outlet->getMedia('images'));
    }

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

        $data = $this->all();

        if ($data['status'] == OutletStatus::TERMINATED) {
            $data['closed_date'] = now();
        } else {
            $data['closed_date'] = null;
        }

        DB::transaction(function () use ($data) {
            $outlet = Outlet::create($data);

            $openingHours = collect($data['opening_hours'])
                ->map(fn ($time, $day) => [
                    'outlet_id' => $outlet->id,
                    'day' => $day,
                    'open_time' => $time['open_time'],
                    'close_time' => $time['close_time'],
                ])
                ->values()
                ->toArray();

            OpeningHour::insert($openingHours);
            $outlet->facilities()->createMany(collect($data['facilities'])->map(fn ($facility) => ['name' => $facility])->toArray());

            $this->uploadMedia($this->featured_image, $outlet, 'featured_image');
            $this->uploadMedia($this->images, $outlet, 'images');
        });
    }

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

        $data = $this->all();

        if ($data['status'] == OutletStatus::TERMINATED->value) {
            $data['closed_date'] = now()->toDateString();
        } else {
            $data['closed_date'] = null;
        }

        DB::transaction(function () use ($data) {
            $this->outlet->update($data);

            foreach ($data['opening_hours'] as $day => $hours) {
                OpeningHour::updateOrCreate(
                    [
                        'outlet_id' => $this->outlet->id,
                        'day' => $day,
                    ],
                    [
                        'open_time' => $hours['open_time'] ?? null,
                        'close_time' => $hours['close_time'] ?? null,
                    ]
                );
            }

            $facilities = collect($data['facilities']);

            foreach ($facilities as $facilityName) {
                $this->outlet->facilities()->updateOrCreate(
                    ['name' => $facilityName],
                    ['name' => $facilityName]
                );
            }

            $this->syncMedia($data['featured_image'], $this->outlet, 'featured_image');
            $this->syncMedia($data['images'], $this->outlet, 'images');

            $this->uploadMedia($this->featured_image, $this->outlet, 'featured_image');
            $this->uploadMedia($this->images, $this->outlet, 'images');
        });
    }
}
