<?php

namespace Daylight\Core\Http\Controllers\Settings;

use Daylight\Core\Http\Controllers\Controller;
use Daylight\Core\Http\Requests\Settings\ShippingZones\StoreShippingZoneRequest;
use Daylight\Core\Http\Requests\Settings\ShippingZones\UpdateShippingZoneRequest;
use Daylight\Core\Models\Shipping\ShippingZone;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Support\Facades\Cache;

class ShippingZoneController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            new Middleware('can:update:settings', only: ['create', 'store', 'update', 'destroy']),
            new Middleware('can:read:settings', only: ['index', 'show', 'edit']),
        ];
    }

    public function index()
    {
        return view('daylight::settings.shipping-zones.index');
    }

    public function create()
    {
        $shippingClasses = (daylightModel('shipping_class'))::all()->map(function ($shippingClass) {
            return [
                'class' => $shippingClass,
                'rules' => [],
            ];
        });

        return view('daylight::settings.shipping-zones.create', [
            'shippingClasses' => $shippingClasses,
            'countries' => (daylightModel('country'))::get(),
        ]);
    }

    public function store(StoreShippingZoneRequest $request)
    {
        $shippingZone = (daylightModel('shipping_zone'))::create([
            ...$request->safe()->only('name'),
            'max_amount' => $request->get('max_amount')
                ? $request->get('max_amount') * 100
                : null,
            'free_shipping_above' => $request->get('free_shipping_above')
                ? $request->get('free_shipping_above') * 100
                : null,
        ]);

        $shippingZone->countries()->sync($request->get('countries'));

        collect($request->get('rules'))
            ->map(function ($rules, $shippingClassId) use ($shippingZone) {
                $shippingZone->shippingZoneRules()
                    ->where('shipping_class_id', $shippingClassId)
                    ->whereNotIn('id', collect($rules)->pluck('id'))
                    ->delete();

                collect($rules)
                    ->each(function ($rule) use ($shippingZone, $shippingClassId) {
                        $shippingZone->shippingZoneRules()->updateOrCreate(
                            [
                                'id' => $rule['id'],
                                'shipping_class_id' => $shippingClassId,
                            ],
                            [
                                'min_weight' => $rule['min_weight'],
                                'max_weight' => $rule['max_weight'],
                                'price' => round($rule['price'] * 100),
                            ]
                        );
                    });
            });

        Cache::forget('countries');

        return redirect()
            ->route('daylight.settings.shipping-zones.edit', $shippingZone)
            ->with('success', __('daylight::settings.shipping_zone_created'));
    }

    public function edit(ShippingZone $shippingZone)
    {
        $shippingZone->loadMissing('shippingZoneRules', 'countries');

        $shippingClasses = (daylightModel('shipping_class'))::all()->map(function ($shippingClass) use ($shippingZone) {
            return [
                'class' => $shippingClass,
                'rules' => $shippingZone->shippingZoneRules->where('shipping_class_id', $shippingClass->id),
            ];
        });

        return view('daylight::settings.shipping-zones.edit', [
            'shippingZone' => $shippingZone,
            'shippingClasses' => $shippingClasses,
            'countries' => (daylightModel('country'))::get(),
        ]);
    }

    public function update(UpdateShippingZoneRequest $request, ShippingZone $shippingZone)
    {
        $shippingZone->update([
            ...$request->safe()->only('name'),
            'max_amount' => $request->get('max_amount')
                ? $request->get('max_amount') * 100
                : null,
            'free_shipping_above' => $request->get('free_shipping_above')
                ? $request->get('free_shipping_above') * 100
                : null,
        ]);

        $shippingZone->countries()->sync($request->get('countries'));

        $rules = collect($request->get('rules'));

        $shippingZone->shippingClasses->each(function ($shippingClass) use ($rules, $shippingZone) {
            if (! isset($rules[$shippingClass->id])) {
                $shippingZone->shippingZoneRules()->where('shipping_class_id', $shippingClass->id)->delete();
            }
        });

        $rules
            ->map(function ($rules, $shippingClassId) use ($shippingZone) {
                $shippingZone->shippingZoneRules()
                    ->where('shipping_class_id', $shippingClassId)
                    ->whereNotIn('id', collect($rules)->pluck('id'))
                    ->delete();

                collect($rules)
                    ->each(function ($rule) use ($shippingZone, $shippingClassId) {
                        $shippingZone->shippingZoneRules()->updateOrCreate(
                            [
                                'id' => $rule['id'],
                                'shipping_class_id' => $shippingClassId,
                            ],
                            [
                                'min_weight' => $rule['min_weight'],
                                'max_weight' => $rule['max_weight'],
                                'price' => round($rule['price'] * 100),
                            ]
                        );
                    });
            });

        Cache::forget('countries');

        return redirect()->route('daylight.settings.shipping-zones.index')
            ->with('success', __('daylight::settings.shipping_zone_updated'));
    }

    public function destroy(ShippingZone $shippingZone)
    {
        $shippingZone->delete();

        Cache::forget('countries');

        return redirect()->route('daylight.settings.shipping-zones.index')
            ->with('success', __('daylight::settings.shipping_zone_deleted'));
    }
}
