<?php

namespace App\Modules\Stock;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Exception;

use Illuminate\Support\Facades\Config;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;
use App\Models\Status;

abstract class AbstractStockPurchaseOrdersControllerREST extends BaseController
{
    protected $model = 'App\Modules\Stock\StockPurchaseOrder';
    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index(Request $request)
    {
        $query = StockPurchaseOrder::query()->select('*')->with('status', 'supplier', 'payment_method');

        $stats = [
            'delivered_orders'    => StockPurchaseOrder::query()->where('status_id', Status::ORDERS_DELIVERED)->count(),
            'total_orders'        => StockPurchaseOrder::query()->count(),
            'cancelled_orders'    => StockPurchaseOrder::query()->where('status_id', Status::ORDERS_CANCELLED)->count(),
        ];

        //Search order by the product serial number
        if ($request->input('serial_number')) {
            $query->whereHas('items', function ($q) use ($request) {
                $q->whereHas('serials', function ($qu) use ($request) {
                    $qu->where('stock_purchase_order_items_serials.serial_number', $request->input('serial_number'));
                });
            });
        } else {
            // Conditional statements based on GET parameters
            if ($request->input('query')) {
                $query = $query->where('reference_number', 'like', '%' . $request->input('query') . '%');
            }
            if ($request->input('status_id')) {
                $query = $query->where('status_id', $request->input('status_id'));
            }
        }

        //Order by id desc
        $query->orderBy('id', 'DESC');

        // Apply limits and execute the query
        $query = $query->paginate($request->input('limit', 20));

        $response = [
            'success'         => true,
            'data'            => $query->getCollection()->toArray(),
            'stats'           => $stats,
            'total'           => $query->total(),
            'current_page'    => $query->currentPage(),
            'last_page'       => $query->lastPage(),
            'from'            => $query->firstItem(),
            'to'              => $query->lastItem(),
        ];

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

    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store(Request $request)
    {
        if (!Auth::user()->hasPermission('edit_stock')) {
            throw new Exception('Permission denied!');
        }

        $data = $request->all();

        // Defensive: Ensure products is an array
        if (!isset($data['products']) || !is_array($data['products']) || empty($data['products'])) {
            return response()->json(['error' => 'The products field is required and must be a non-empty array.'], 400);
        }

        $items_cost = 0;

        if ($request->input('delivery_vat_included')) {
            $data['delivery_cost'] = round($data['delivery_cost'] / (1 + Config::get('settings.vat') / 100), 4);
        }
        if ($request->input('payment_id')) {
            $data['payments_id'] = $request->input('payment_id');
        }

        if ($request->input('discount_vat_included')) {
            $data['discount_amount'] = round($data['discount_amount'] / (1 + Config::get('settings.vat') / 100), 4);
        }

        // Gets the total items cost
        foreach ($data['products'] as $item) {
            if ($request->input('items_vat_included')) {
                $item['unit_cost'] = round($item['unit_cost'] / (1 + Config::get('settings.vat') / 100), 4);
            }
            $items_cost += $item['unit_cost'] * $item['units'];
        }

        $data['items_cost'] = $items_cost;

        //Calculates the total vat
        $data['vat'] = Config::get('settings.vat');

        //Creates the status as "ordered"
        $data['status_id'] = Status::query()->where('for', 'orders')->where('name', 'Ordered')->first()->id;

        $order = '';

        return DB::transaction(function () use ($data, &$order, $request) {
            try {
                $order = StockPurchaseOrder::create($data);
                if (!$order->id) {
                    DB::rollback();
                    return response()->json(['error' => $order->errors->all()], 404);
                }
                
                foreach ($data['products'] as $item) {
                    if ($request->input('items_vat_included')) {
                        $item['unit_cost'] = number_format($item['unit_cost'] / (1 + Config::get('settings.vat') / 100), 2, '.', '');
                    }

                    //Create the items for the purchase order
                    $orderItem = StockPurchaseOrderItem::create([
                        'stock_purchase_order_id' => $order->id,
                        'stock_id'                => $item['id'],
                        'unit_cost'               => $item['unit_cost'],
                        'unit_vat'                => number_format($item['unit_cost'] * Config::get('settings.vat') / 100, 2, '.', ''),
                        'quantity'                => $item['units'],
                    ]);

                    if (!$orderItem->id) {
                        DB::rollback();
                        return response()->json(['error' => $orderItem->errors->all()], 404);
                    }
                }

                // Generate purchase order number locally
                $order->purchase_order_number = 'PO-' . str_pad($order->id, 6, '0', STR_PAD_LEFT);
                $order->save();

            } catch (Exception $e) {
                return response()->json(['error' => $e->getMessage()], 400);
            }

            $order->load('items', 'items.stock', 'supplier', 'payment_method');

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

    /**
     * Manually sync a purchase order to Xero (deprecated - Xero integration removed)
     *
     * @param Request $request
     * @param int $id
     * @return Response
     */
    public function syncToXero(Request $request, $id)
    {
        return response()->json([
            'success' => false,
            'message' => 'Xero integration has been disabled for stock purchase orders'
        ], 501);
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function show($id)
    {
        $order = StockPurchaseOrder::findOrFail($id);
        $order->load('items', 'items.stock', 'supplier', 'items.serials', 'payment_method');

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

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function update($id, Request $request)
    {
        if (!Auth::user()->hasPermission('edit_stock')) {
            throw new Exception('Permission denied!');
        }

        try {
            $classname = $this->model;
            $order = $classname::findOrFail($id);

            if (!$order->id) {
                return response()->json(['error' => 'Order not found.'], 404);
            }

            DB::transaction(function () use (&$order, $request) {
                $order->fill($request->all());

                if (!$order->save()) {
                    throw new Exception($order->errors->all(), 1);
                }
            });

            $order->load('items', 'items.stock', 'supplier', 'payment_method');

            return $order;
        } catch (Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     *
     * @return Response
     */
    public function destroy($id)
    {
        if (!Auth::user()->hasPermission('edit_stock')) {
            throw new Exception('Permission denied!');
        }

        //Check first if there is any stock marked as received
        $justified_items = StockPurchaseOrderItem::query()->where('stock_purchase_order_id', $id)->where('received_quantity', '>', 0)->count();
        if ($justified_items > 0) {
            return response()->json(['error' => 'An order can not be cancelled when some items has been marked as received or refused.'], 404);
        }

        return DB::transaction(function () use ($id) {
            $purchasOrder = StockPurchaseOrder::findOrFail($id);

            // Mark all the product as refused
            foreach ($purchasOrder->items as $item) {
                $item->refuseAll();
            }

            $purchasOrder->status_id = Status::query()->where('for', 'orders')->where('name', 'Cancelled')->first()->id;
            if (!$purchasOrder->save()) {
                throw new Exception('Error cancelling the purchase order.', 1);
            }

            return response()->json($purchasOrder->toArray());
        });
    }
}
