<?php

namespace App\Http\Controllers\Admin;

use AllowDynamicProperties;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\Order\OrderBulkDestroyRequest;
use App\Models\{Country, Coupon, Order, Plan, PricingTier, Product, State, User};
use App\Services\CartService;
use App\Services\OrderService;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Laracasts\Flash\Flash;

#[AllowDynamicProperties]
class AdminOrderController extends Controller
{
    protected array $data = [];
    private $cart;

    public function __construct(CartService $cart, OrderService $orderService)
    {
        $this->data['title'] = 'Orders';
        $this->orderService = $orderService;
        $this->cart = $cart;
    }

    public function index()
    {
        $this->data['allOrders'] = $this->orderService->getOneTimeOrders();

        $this->data['orderStatuses'] = $this->orderService->getOneTimeOrderStatusCounts();

        // Get filter values from the request
        $searchTerm = request('search');
        $status = request('status');
        $userId = request('user_id');
        $discountCode = request('discount_code');
        $paymentMethod = request('payment_method');

        if ($searchTerm !== null || $status !== null || $userId !== null || $discountCode !== null || $paymentMethod !== null) {
            $this->data['orders'] = $this->orderService->filterOneTimeOrders($searchTerm, $status, $userId, $discountCode, $paymentMethod, $perPage=10);
        } else {
            $this->data['orders'] = $this->orderService->paginateOneTimeOrders($perPage=10);
        }

        return view('admin.order.index', $this->data);
    }

    public function create()
    {
        $this->cart->clearCart();
        $this->data['title'] = 'Add new Order';
        $this->data['users'] = User::all();
        $this->data['products'] = Product::all();
        $this->data['countries'] = Country::all();

        return view('admin.order.create', $this->data);
    }

    public function getBillingAddress($userId)
    {
        $user = User::with(['billingAddress.country', 'billingAddress.state'])->find($userId);

        if ($user && $user->billingAddress) {
            $billingAddress = $user->billingAddress->toArray();

            $billingAddress['states'] = State::where('country_id', $user->billingAddress->country_id)->get();

            return response()->json($billingAddress);
        }

        return response()->json([], 404);
    }

    /**
     * @throws ValidationException
     */
    public function setBillingAddress(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'user_id' => 'required|string',
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'address' => 'required|string|max:255',
            'city' => 'required|string|max:255',
            'zip' => 'required|string|max:10',
            'phone_number' => 'required|string|max:15|regex:/^[0-9\-\+\s]+$/',
            'email' => 'required|string|email|max:255',
            'country_id' => ['required', Rule::exists('countries', 'id')],
            'state_id' => ['required', Rule::exists('states', 'id')],
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => 'error',
                'errors' => $validator->errors(),
            ], 422);
        }

        $validatedData = $validator->validated();

        $user = User::find($request->input('user_id'));

        if (!$user) {
            return response()->json([
                'status' => 'error',
                'message' => 'User not found!',
            ], 404);
        }

        $billingAddress = $user->billingAddress()->updateOrCreate(['user_id' => $user->id], $validatedData);

        $billingAddress->load(['country', 'state']);

        return response()->json([
            'status' => 'success',
            'message' => 'Billing details updated successfully!',
            'billingInfo' => $billingAddress->toArray(),
        ]);
    }

    public function getPlans($productId)
    {
        $plans = Plan::where('product_id', $productId)->get();
        return response()->json($plans);
    }

    public function getPricingTiers($planId)
    {
        $pricingTiers = PricingTier::with(['addons'])->where('plan_id', $planId)->get();
        return response()->json($pricingTiers);
    }

    public function getStates($countryId)
    {
        $states = State::where('country_id', $countryId)->get();
        return response()->json($states);
    }

    public function addToCart(Request $request)
    {
        $this->cart->addToCart($request->input('pricing_tier_id'), 'pricing_tier');

        return $this->getCart();
    }

    public function addAddon(Request $request)
    {
        $addonIds = $request->all();

        foreach ($addonIds as $addonId) {
            $this->cart->addToCart($addonId, 'addon');
        }

        return $this->getCart();
    }

    public function removeFromCart(Request $request)
    {
        $rowId = $request->input('rowId');
        try {
            $this->cart->removeToCart($rowId);
            return $this->getCart();
        } catch (\Exception $e) {
            return response()->json([], 404);
        }
    }

    public function applyCoupon(Request $request)
    {
        try {
            $couponCode = $request->input('code');
            $coupon = Coupon::where('code', $couponCode)->first();
            $this->cart->applyCouponCode($coupon);
            return $this->getCart();
        } catch (\Exception $e) {
            return response()->json([], 404);
        }
    }

    public function removeCoupon()
    {
        try {
            session()->forget('discounted');
            session()->forget('discount_amount');
            session()->forget('coupon_code');
            session()->forget('coupon_id');
            session()->forget('on_subtotal');
            return $this->getCart();
        } catch (\Exception $e) {
            return response()->json([], 404);
        }
    }

    private function getCart()
    {
        $sub_total = $this->cart->getSubtotal();
        $total = $this->cart->getTotal();
        $tax = get_tax_rate();
        $discount = $this->cart->discountFloat();
        $items = $this->cart->getCartItems();
        $itemsCount = $this->cart->countItems();

        return response()->json([
            'subTotal' => ch_format_price($sub_total),
            'total' => ch_format_price($total),
            'tax' => ch_format_price($tax),
            'discount' => ch_format_price($discount),
            'items' => $items,
            'itemsCount' => $itemsCount,
        ]);
    }

    public function store(Request $request)
    {
        $this->orderService->create($this->cart, \request()->all(), \request('user_id'));

        return redirect()->route('ch-admin.order.index');
    }

    public function show(Request $request, $id)
    {
        $this->data['order'] = Order::with('items.customFields')->findOrFail($id);
        $this->data['attachments'] = json_encode($this->data['order']->getMedia('attachments')->map(function ($media) {
            return [
                'id' => $media->id,
                'image_url' => $media->getUrl('thumbnail'),
                'size' => $media->size
            ];
        }));
        return view('admin.order.show', $this->data);
    }

    public function update(Request $request, $order_id)
    {
        try {
            $order = $this->orderService->getOrderById($order_id);
            if ($order->payment_method == 'offline_payments') {
                $this->orderService->update($order, 'transaction_id', $request->transaction_id);
            }

            if ($order->status != (int)$request->input('status')) {
                $this->orderService->handlePostPaymentFlow($order, (int)$request->input('status'));
            }

            Flash::success('Order updated.');
        } catch (\Exception $e) {
            Flash::error('Failed to update order: ' . $e->getMessage());
        }

        return redirect()->route('ch-admin.order.show', [$order->id]);
    }

    public function destroy(Order $order)
    {
        $order->order_details()->delete();

        $order->items->each(function ($item) {

            $item->meta()->delete();

            $item->delete();
        });

        $order->customFields->each(function ($field) {
            if ($field->type == 'file' && !empty($field->file)) {

                $file = $field->file;

                $file->meta->each(function ($meta_file) {
                    if (file_exists(storage_path("app/" . $meta_file->path))) {
                        unlink(storage_path("app/" . $meta_file->path));
                    }
                    $meta_file->delete();
                });

                $file_path = "app/{$file->directory}/{$file->filename}.{$file->extension}";
                if (file_exists(storage_path($file_path))) {
                    unlink(storage_path($file_path));
                }
                $file->delete();
            }

            $field->delete();
        });

        $order->delete();

        Flash::success('Order deleted successfully.');

        return redirect()->back();
    }

    public function bulkDestroy(OrderBulkDestroyRequest $request)
    {
        $validateData = $request->validated();

        try {
            $this->orderService->deleteOrders($validateData);
            Flash::success('Orders deleted successfully.');
            return response()->json(['success' => true]);
        } catch (\Exception $ex) {
            Flash::error('Failed to delete orders: ' . $ex->getMessage());
            return response()->json(['success' => false]);
        }
    }
}
