<?php

namespace App\Http\Controllers\Shop;

use App\Repositories\Core\User\ShopCart;
use App\Repositories\Shop\Baskets;
use App\Repositories\Shop\CustomerAddresses;
use App\Repositories\Shop\Customers;
use App\Repositories\Shop\Offers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;

class CustomerController extends Controller
{
    public function profile()
    {
        $data = Customers::editProfile(Customers::getId());

        return view('Shop.Customers.profile', $data);
    }

    public static function checkAuth()
    {
        if (Customers::isNotConnected()) {
            return redirect()->route('Shop.login');
        }
    }

    public function modalProfile($id = false)
    {
        $data = [
            'customer' => Customers::get($id),
        ];

        return view('Shop.Customers.partials.registration', $data);
    }

    public function edit()
    {
        $data = [
            'customer' => Customers::edit(Customers::getId()),
        ];

        return view('Shop.Customers.edit', $data);
    }

    public function storeProfileAjax(Request $request)
    {
        $data = $request->all();

        if (array_key_exists('default_sale_channel_id', $data)) {
            $customer = Customers::get(Customers::getId());
            $newSaleChannelId = (int) $data['default_sale_channel_id'];
            $currentSaleChannelId = (int) ($customer->default_sale_channel_id ?? 0);

            if ($newSaleChannelId && $newSaleChannelId !== $currentSaleChannelId && ShopCart::count() > 0) {
                $cartItems = ShopCart::getContent();
                $unavailable = [];

                foreach ($cartItems as $item) {
                    $offerId = (int) $item->id;

                    if (! Offers::getPrice($offerId, 1, $newSaleChannelId)) {
                        $offer = Offers::get($offerId, ['article']);
                        $unavailable[] = $offer->article->name ?? $item->name;

                        if (count($unavailable) >= 3) {
                            break;
                        }
                    }
                }

                if (! empty($unavailable)) {
                    $list = implode(', ', $unavailable);

                    return response()->json([
                        'error' => 1,
                        'message' => __('Certains articles de votre panier ne sont pas disponibles dans ce canal : :products. Merci de finaliser votre commande ou de retirer ces articles avant de changer de canal.', ['products' => $list]),
                    ], 422);
                }
            }
        }

        $customerId = $data['id'] ?? Customers::getId();
        $requestedDefaultSaleChannelId = $data['default_sale_channel_id'] ?? null;
        $hasDefaultSaleChannelColumn = Schema::hasColumn('shop_customers', 'default_sale_channel_id');

        if (! $hasDefaultSaleChannelColumn) {
            unset($data['default_sale_channel_id']);
        }

        $customer = Customers::store($data);

        if (! $customer) {
            return response()->json([
                'error' => 1,
                'message' => __('Impossible de mettre à jour votre profil pour le moment.'),
            ], 422);
        }

        if ($hasDefaultSaleChannelColumn && $requestedDefaultSaleChannelId !== null) {
            Customers::setDefaultSaleChannel($customerId, $requestedDefaultSaleChannelId);
        }

        $freshCustomer = Customers::get($customerId, ['sale_channels']);
        Customers::guard()->setUser($freshCustomer);

        if ($requestedDefaultSaleChannelId !== null) {
            session(['shop.default_sale_channel_id' => $requestedDefaultSaleChannelId]);
            Baskets::refreshPrices((int) $requestedDefaultSaleChannelId);
        }

        return response()->json(['error' => 0]);
    }

    public function store(Request $request)
    {
        $data = $request->all();

        $validator = Validator::make($data, [
            'phone' => 'required|max:30',
        ], [
            'phone.required' => __('Le numéro de téléphone est obligatoire.'),
        ]);

        if ($validator->fails()) {
            return redirect()->route('Shop.Customers.edit')
                ->withInput()
                ->withErrors($validator->errors(), 'registration');
        }

        $passwordError = $this->handlePasswordChange($request);
        if ($passwordError) {
            return redirect()->route('Shop.Customers.edit')
                ->with('growl', [$passwordError, 'danger']);
        }

        unset($data['current-password'], $data['new-password'], $data['new-password_confirmation']);

        $customer = Customers::storeFull($data);

        $growl = $request->filled('new-password')
            ? [__('Profil et mot de passe mis à jour.'), 'success']
            : [__('Profil mis à jour.'), 'success'];

        return redirect()->route('Shop.Customers.edit')->with('growl', $growl);
    }

    protected function handlePasswordChange(Request $request)
    {
        if (! $request->filled('new-password')) {
            return null;
        }

        $customer = Customers::get(Customers::getId());

        if (! $customer) {
            return __('Impossible de modifier le mot de passe.');
        }

        if (! Hash::check($request->input('current-password'), $customer->password)) {
            return __('Le mot de passe actuel est incorrect.');
        }

        if ($request->input('new-password') !== $request->input('new-password_confirmation')) {
            return __('Les mots de passe ne correspondent pas.');
        }

        $newPassword = $request->input('new-password');

        if (strlen($newPassword) < 8) {
            return __('Le mot de passe doit contenir au moins 8 caractères.');
        }

        if (! preg_match('/[a-z]/', $newPassword)) {
            return __('Le mot de passe doit contenir au moins une lettre minuscule.');
        }

        if (! preg_match('/[A-Z]/', $newPassword)) {
            return __('Le mot de passe doit contenir au moins une lettre majuscule.');
        }

        if (! preg_match('/[0-9]/', $newPassword)) {
            return __('Le mot de passe doit contenir au moins un chiffre.');
        }

        if (! preg_match('/[^A-Za-z0-9]/', $newPassword)) {
            return __('Le mot de passe doit contenir au moins un caractère spécial.');
        }

        $customer->password = Hash::make($request->input('new-password'));
        $customer->save();

        return null;
    }

    public function storeAddress(Request $request)
    {
        if (Customers::isNotConnected()) {
            return response()->json(['message' => __('Authentification requise.')], 403);
        }

        $prefix = $request->input('prefix');
        $types = ['deliveries' => 1, 'invoices' => 2];

        if (! array_key_exists($prefix, $types)) {
            return response()->json(['message' => __('Type d\'adresse inconnu.')], 422);
        }

        $addressData = $request->input($prefix, []);

        $validator = Validator::make($addressData, [
            'name' => ['nullable', 'string', 'max:150'],
            'address' => ['required', 'string', 'max:255'],
            'address2' => ['nullable', 'string', 'max:255'],
            'zipcode' => ['required', 'string', 'max:30'],
            'city' => ['required', 'string', 'max:255'],
        ], [
            'address.required' => __('Merci de renseigner l\'adresse.'),
            'zipcode.required' => __('Merci de renseigner le code postal.'),
            'city.required' => __('Merci de renseigner la ville.'),
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => __('Merci de vérifier les informations saisies.'),
                'errors' => $validator->errors(),
            ], 422);
        }

        $data = $validator->validated();
        $customerId = Customers::getId();
        $data['customer_id'] = $customerId;
        $data['type'] = $types[$prefix];

        if (empty($data['name'])) {
            $data['name'] = Customers::getName($customerId);
        }

        $address = CustomerAddresses::store($data);
        CustomerAddresses::setDefault($customerId, $address->id, $types[$prefix]);

        $html = view('Shop.Customers.partials.address_item', [
            'address' => $address->toArray(),
            'prefix' => $prefix,
            'inputName' => $request->input('input_name'),
            'with_name' => true,
            'selected' => $address->id,
        ])->render();

        return response()->json([
            'success' => true,
            'html' => $html,
            'message' => __('Adresse enregistrée.'),
            'id' => $address->id,
        ]);
    }

    public function delete_address($id)
    {
        $address = CustomerAddresses::get($id);

        if (! $address || (int) $address->customer_id !== (int) Customers::getId()) {
            abort(404);
        }

        $remaining = CustomerAddresses::getModel()
            ->byCustomer($address->customer_id)
            ->byType($address->type)
            ->count();

        if ($remaining <= 1) {
            return redirect()->route('Shop.Customers.edit')
                ->with('growl', [__('Vous devez conserver au moins une adresse par type.'), 'warning']);
        }

        CustomerAddresses::destroy($id);
        CustomerAddresses::ensureDefault($address->customer_id, $address->type);

        return redirect()->route('Shop.Customers.edit')
            ->with('growl', [__('Adresse supprimée.'), 'success']);
    }
}
