<?php

namespace App\Http\Controllers\Modules\Purchase;

use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderItem;
use App\Models\CustomerVendor;
use App\Models\PurchaseQuotation;
use App\Models\RfqType;
use App\Models\StockItem;
use App\Services\Purchase\PurchaseOrderService;
use App\Http\Requests\Purchase\StorePurchaseOrderRequest;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Unified Purchase Order Controller
 *
 * Handles purchase order management for all roles.
 * Reference: SuperAdminPurchaseController
 */
class PurchaseOrderController extends Controller
{
    use HasRoleViews;

    protected PurchaseOrderService $purchaseOrderService;

    public function __construct(PurchaseOrderService $purchaseOrderService)
    {
        $this->purchaseOrderService = $purchaseOrderService;
    }

    /**
     * Display the purchase order creation form
     * Alias: purchasePage() for backward compatibility
     */
    public function purchasePage()
    {
        return $this->create();
    }

    /**
     * Display the purchase order list page
     * Alias: purchaseDetails() for backward compatibility
     */
    public function purchaseDetails()
    {
        return $this->index();
    }

    /**
     * Display the purchase order creation form
     */
    public function create()
    {
        Log::info("{$this->getCurrentRole()} accessed Purchase Order Form");

        $rfqTypes = RfqType::all();
        $stock_items = StockItem::all();

        return $this->roleView('purchase.purchaseorder', compact('rfqTypes', 'stock_items'));
    }

    /**
     * Display the purchase order list page
     */
    public function index()
    {
        Log::info("{$this->getCurrentRole()} accessed Purchase Details Page");
        $purchaseOrders = PurchaseOrder::with('vendor')->orderBy('id', 'desc')->get();
        return $this->roleView('purchase.purchasedetails', compact('purchaseOrders'));
    }

    /**
     * Generate PO ID (AJAX)
     */
    public function generatePOId(): JsonResponse
    {
        try {
            $lastPo = PurchaseOrder::orderByDesc('id')->first();
            if ($lastPo && isset($lastPo->purchase_order_no)) {
                $lastId = intval(preg_replace('/[^0-9]/', '', substr($lastPo->purchase_order_no, -4)));
            } else {
                $lastId = 0;
            }
            $newId = str_pad($lastId + 1, 4, '0', STR_PAD_LEFT);
            $poId = "UEPL/PO/{$newId}";

            return response()->json(['so_id' => $poId]);
        } catch (\Exception $e) {
            return response()->json(['so_id' => 'UEPL/PO/0001']);
        }
    }

    /**
     * Get vendors for dropdown (AJAX)
     */
    public function getVendors(): JsonResponse
    {
        $vendors = CustomerVendor::where('company_role', 'Vendor')
            ->orWhere('company_role', 'Both')
            ->select('id', 'company', 'billing_address', 'gstno', 'mobile', 'email')
            ->orderBy('company')
            ->get();

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

    /**
     * Get available quotations for dropdown (AJAX)
     */
    public function getQuotations(): JsonResponse
    {
        $quotations = PurchaseQuotation::where('status', 'approved')
            ->whereDoesntHave('purchaseOrder')
            ->orderBy('id', 'desc')
            ->get(['id', 'quotation_no']);

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

    /**
     * Get quotation details by ID (AJAX)
     */
    public function getQuotationById(int $id): JsonResponse
    {
        $quotation = PurchaseQuotation::with(['items', 'vendor'])->find($id);

        if (!$quotation) {
            return response()->json(['error' => 'Quotation not found'], 404);
        }

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

    /**
     * Store a newly created purchase order
     */
    public function store(StorePurchaseOrderRequest $request): JsonResponse
    {
        Log::info('[PurchaseOrder] Store called');

        try {
            Log::info('[PurchaseOrder] Store processing started');

            // Validation handled by StorePurchaseOrderRequest
            $validated = $request->validated();

            Log::info('[PurchaseOrder] Validation passed', $validated);

            DB::beginTransaction();

            $purchaseOrder = PurchaseOrder::create([
                'purchase_order_no' => $request->input('sOrderNo'),
                'purchase_order_date' => $request->input('sOrderDate'),
                'quotation_no' => $request->input('quotationNo2'),
                'quotation_date' => $request->input('quotationDate'),
                'customer_ref_no' => $request->input('custRefNo'),
                'company_name' => $request->input('soCompanyName'),
                'vendor_id' => $request->input('soCompanyId'),
                'company_address' => $request->input('soCompanyAddress'),
                'company_gstn' => $request->input('soCompanyGSTN'),
                'company_phone' => $request->input('soCompanyPhone'),
                'company_email' => $request->input('soCompanyEmail'),
                'bill_address' => $request->input('billAddress'),
                'ship_address' => $request->input('shipAddress'),
                'inr_in_words' => $request->input('inr_in_words'),
                'subtotal' => $request->input('totalAmount'),
                'sgst_amount' => $request->input('sgstA'),
                'cgst_amount' => $request->input('cgstA'),
                'igst_amount' => $request->input('IgstA'),
                'round_up' => $request->input('roundUp'),
                'grand_total' => $request->input('grandTotal'),
                'rfq_no' => $request->input('rfqNo'),
                'rfq_date' => $request->input('rfqDate'),
                'description' => $request->input('projectDescription'),
                'delivery_terms' => $request->input('deliveryTerms'),
                'additional_charges' => $request->input('additionalCharges'),
                'note' => $request->input('note'),
                'status' => 'pending',
            ]);

            Log::info('[PurchaseOrder] PurchaseOrder created', ['id' => $purchaseOrder->id]);

            $items = $request->input('tableProducts');
            if (!is_array($items)) {
                throw new \Exception("Invalid or missing 'tableProducts' array in request");
            }

            foreach ($items as $item) {
                PurchaseOrderItem::create([
                    'purchase_order_id' => $purchaseOrder->id,
                    'sl_no' => $item['sl_no'] ?? null,
                    'item' => $item['item'] ?? null,
                    'description' => $item['description'] ?? null,
                    'req_by_date' => $item['req_by_date'] ?? null,
                    'quantity' => $item['quantity'] ?? 0,
                    'uom' => $item['uom'] ?? null,
                    'unit_rate' => $item['unit_rate'] ?? 0,
                    'tds' => $item['tds'] ?? 0,
                    'discount' => $item['discount'] ?? 0,
                    'value' => $item['value'] ?? 0,
                    'sgst' => $item['sgst'] ?? 0,
                    'cgst' => $item['cgst'] ?? 0,
                    'igst' => $item['igst'] ?? 0,
                    'amount' => $item['amount'] ?? 0,
                ]);
            }

            DB::commit();

            return response()->json([
                'message' => 'Purchase Order saved successfully!',
                'id' => $purchaseOrder->id,
            ], 201);

        } catch (\Illuminate\Validation\ValidationException $e) {
            DB::rollBack();
            Log::error('[PurchaseOrder] Validation failed', ['errors' => $e->validator->getMessageBag()]);
            return response()->json([
                'error' => 'Validation failed',
                'details' => $e->validator->getMessageBag(),
            ], 422);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('[PurchaseOrder] Exception occurred', ['message' => $e->getMessage()]);
            return response()->json([
                'error' => 'Server error occurred',
                'message' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Display the specified purchase order
     */
    public function show(int $id)
    {
        $po = PurchaseOrder::with(['items', 'vendor', 'items.stockItem'])->findOrFail($id);
        return $this->roleView('purchase.show', compact('po'));
    }

    /**
     * Get purchase order by ID (AJAX)
     */
    public function getPurchaseOrderById(int $id): JsonResponse
    {
        $order = PurchaseOrder::with(['items', 'vendor'])->findOrFail($id);
        return response()->json($order);
    }

    /**
     * Display the edit form
     */
    public function edit(int $id)
    {
        $po = PurchaseOrder::with('items', 'vendor')->findOrFail($id);
        $stockItems = StockItem::all();
        $vendors = CustomerVendor::where('company_role', 'Vendor')
            ->orWhere('company_role', 'Both')
            ->select('id', 'company')
            ->get();
        $editOrderId = $id;

        return $this->roleView('purchase.edit', compact('po', 'vendors', 'editOrderId', 'stockItems'));
    }

    /**
     * Update the specified purchase order
     */
    public function update(Request $request, int $id): JsonResponse
    {
        Log::info("[PurchaseOrder] Update called for ID: $id");

        try {
            $validated = $request->validate([
                'soNo1' => 'required|unique:purchase_orders,purchase_order_no,' . $id,
                'soDate' => 'required|date',
                'soCompanyName' => 'required|string',
                'grandTotal' => 'required|numeric',
            ]);

            DB::beginTransaction();

            $purchaseOrder = PurchaseOrder::findOrFail($id);

            $purchaseOrder->update([
                'purchase_order_no' => $request->input('soNo1'),
                'purchase_order_date' => $request->input('soDate'),
                'company_name' => $request->input('soCompanyName'),
                'vendor_id' => $request->input('soCompanyId'),
                'quotation_no' => $request->input('quotationId'),
                'quotation_date' => $request->input('quotationDate'),
                'customer_ref_no' => $request->input('custRefNo'),
                'company_address' => $request->input('soCompanyAddress'),
                'company_gstn' => $request->input('soCompanyGSTN'),
                'company_phone' => $request->input('soCompanyPhone'),
                'company_email' => $request->input('soCompanyEmail'),
                'bill_address' => $request->input('billAddress'),
                'ship_address' => $request->input('shipAddress'),
                'inr_in_words' => $request->input('inr_in_words'),
                'subtotal' => $request->input('totalAmount'),
                'sgst_amount' => $request->input('sgstA'),
                'cgst_amount' => $request->input('cgstA'),
                'igst_amount' => $request->input('IgstA'),
                'round_up' => $request->input('roundUp'),
                'grand_total' => $request->input('grandTotal'),
                'rfq_no' => $request->input('rfqNo'),
                'rfq_date' => $request->input('rfqDate'),
                'description' => $request->input('projectDescription'),
                'delivery_terms' => $request->input('deliveryTerms'),
                'additional_charges' => $request->input('additionalCharges'),
                'note' => $request->input('note'),
            ]);

            // Replace existing items
            $purchaseOrder->items()->delete();

            $items = $request->input('tableProducts');
            if (!is_array($items)) {
                throw new \Exception("Invalid or missing 'tableProducts' array in request");
            }

            foreach ($items as $item) {
                PurchaseOrderItem::create([
                    'purchase_order_id' => $purchaseOrder->id,
                    'sl_no' => $item['sl_no'] ?? null,
                    'item' => $item['item'] ?? null,
                    'description' => $item['description'] ?? null,
                    'req_by_date' => $item['req_by_date'] ?? null,
                    'quantity' => $item['quantity'] ?? 0,
                    'uom' => $item['uom'] ?? null,
                    'unit_rate' => $item['unit_rate'] ?? 0,
                    'tds' => $item['tds'] ?? 0,
                    'discount' => $item['discount'] ?? 0,
                    'value' => $item['value'] ?? 0,
                    'sgst' => $item['sgst'] ?? 0,
                    'cgst' => $item['cgst'] ?? 0,
                    'igst' => $item['igst'] ?? 0,
                    'amount' => $item['amount'] ?? 0,
                ]);
            }

            DB::commit();

            return response()->json([
                'message' => 'Purchase Order updated successfully!',
                'id' => $purchaseOrder->id,
            ], 200);

        } catch (\Illuminate\Validation\ValidationException $e) {
            DB::rollBack();
            return response()->json([
                'error' => 'Validation failed',
                'details' => $e->validator->getMessageBag(),
            ], 422);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('[PurchaseOrder] Exception occurred', ['message' => $e->getMessage()]);
            return response()->json([
                'error' => 'Server error occurred',
                'message' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Remove the specified purchase order
     */
    public function destroy(int $id): JsonResponse
    {
        // Authorization: Only SuperAdmin or Manager can delete
        if (!$this->isSuperAdmin() && !$this->isManager()) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized. Only SuperAdmin or Manager can delete purchase orders.',
            ], 403);
        }

        try {
            $order = PurchaseOrder::findOrFail($id);

            // Prevent deletion of approved orders by non-SuperAdmin
            if ($order->status === PurchaseOrder::STATUS_APPROVED && !$this->isSuperAdmin()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot delete approved orders. Only SuperAdmin can delete approved records.',
                ], 403);
            }

            // Check if order has a related GRN
            if ($order->grn) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot delete purchase order with existing GRN.',
                ], 403);
            }

            // Check if order has a related purchase invoice
            if ($order->purchase) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot delete purchase order with existing purchase invoice.',
                ], 403);
            }

            $order->items()->delete();
            $order->delete();

            return response()->json(['success' => true, 'message' => 'Purchase Order deleted successfully']);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Failed to delete order'], 500);
        }
    }

    /**
     * Approve a purchase order (SuperAdmin only)
     */
    public function approve(int $id): JsonResponse
    {
        if (!$this->isSuperAdmin()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        try {
            $po = PurchaseOrder::findOrFail($id);
            $po->status = 'approved';
            $po->save();

            return response()->json(['message' => 'Purchase Order approved successfully']);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to approve order'], 500);
        }
    }

    /**
     * Reject a purchase order (SuperAdmin only)
     */
    public function reject(int $id): JsonResponse
    {
        if (!$this->isSuperAdmin()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        try {
            $po = PurchaseOrder::findOrFail($id);
            $po->status = 'rejected';
            $po->save();

            return response()->json(['message' => 'Purchase Order rejected']);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to reject order'], 500);
        }
    }

    /**
     * Print purchase order
     */
    public function print(int $id)
    {
        $po = PurchaseOrder::with(['items', 'vendor'])->findOrFail($id);
        return $this->roleView('purchase.print', compact('po'));
    }
}
