<?php

namespace App\Http\Controllers\Modules\Sales;

use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Models\SalesOrder;
use App\Models\SalesOrderItem;
use App\Models\CustomerVendor;
use App\Models\Quotation;
use App\Services\Sales\SalesOrderService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Unified Sales Order Controller
 *
 * Handles sales order management for all roles.
 * Views are automatically resolved based on the logged-in user's role.
 * Reference: SuperAdminSalesController
 */
class SalesOrderController extends Controller
{
    use HasRoleViews;

    protected SalesOrderService $salesOrderService;

    public function __construct(SalesOrderService $salesOrderService)
    {
        $this->salesOrderService = $salesOrderService;
    }

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

    /**
     * Display the sales order creation form
     */
    public function create()
    {
        Log::info("{$this->getCurrentRole()} accessed Sales Order Form");
        return $this->roleView('sales.salesorder');
    }

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

    /**
     * Display the sales order list page
     */
    public function index()
    {
        Log::info("{$this->getCurrentRole()} accessed Sales Details Page");
        $orders = SalesOrder::with('customer')->get();
        return $this->roleView('sales.salesdetails', compact('orders'));
    }

    /**
     * Generate Sales Order ID (AJAX)
     */
    public function generateSOId(): JsonResponse
    {
        try {
            $soId = $this->salesOrderService->generateSalesOrderNumber();
            return response()->json(['so_id' => $soId]);
        } catch (\Exception $e) {
            return response()->json(['so_id' => 'UEPL/SO/0001']);
        }
    }

    /**
     * Generate GRN ID (AJAX)
     */
    public function generateGRNId(): JsonResponse
    {
        try {
            $lastGrn = SalesOrder::orderByDesc('id')->first();

            if ($lastGrn && isset($lastGrn->grn_no)) {
                $lastId = intval(preg_replace('/[^0-9]/', '', substr($lastGrn->grn_no, -4)));
            } else {
                $lastId = 0;
            }

            $newId = str_pad($lastId + 1, 4, '0', STR_PAD_LEFT);
            $grnId = "UEPL/GRN/{$newId}";

            return response()->json(['grn_id' => $grnId]);
        } catch (\Exception $e) {
            return response()->json(['grn_id' => 'UEPL/GRN/0001']);
        }
    }

    /**
     * Get all customers for dropdown (AJAX)
     */
    public function getCustomers(): JsonResponse
    {
        try {
            $customers = CustomerVendor::select('id', 'company')->get();
            return response()->json($customers);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load companies'], 500);
        }
    }

    /**
     * Get customer details by ID (AJAX)
     */
    public function getCustomerById(int $id): JsonResponse
    {
        try {
            $customer = CustomerVendor::find($id);

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

            return response()->json([
                'billingAddress' => $customer->billing_address,
                'gstNo' => $customer->gstno,
                'mobile' => $customer->mobile,
                'email' => $customer->email,
            ]);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to fetch customer details'], 500);
        }
    }

    /**
     * Get approved quotations for dropdown (AJAX)
     */
    public function getQuotations(): JsonResponse
    {
        $quotations = Quotation::where('status', 'approved')
            ->whereNotIn('quotation_no', function ($query) {
                $query->select('quotation_no')
                    ->from('sales_orders')
                    ->whereNotNull('quotation_no');
            })
            ->orderBy('id', 'desc')
            ->get(['id', 'quotation_no']);

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

    /**
     * Get quotation details by ID (AJAX)
     */
    public function getQuotationById(int $id): JsonResponse
    {
        $quotation = Quotation::with('customer', 'rfq')
            ->whereHas('customer', function ($q) {
                $q->where('company_role', '!=', 'Vendor');
            })
            ->where('id', $id)
            ->first();

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

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

    /**
     * Get non-vendor quotations (AJAX)
     */
    public function getNonVendorQuotations(): JsonResponse
    {
        $quotations = Quotation::with('customer')
            ->whereHas('customer', function ($q) {
                $q->where('company_role', '!=', 'Vendor');
            })->get();

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

    /**
     * Store a newly created sales order
     */
    public function store(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'soNo1' => 'required|unique:sales_orders,sales_order_no',
                'soDate' => 'required|date',
                'customerSO' => 'nullable|file|mimes:pdf,jpg,jpeg,png,doc,docx|max:10240',
            ]);

            DB::beginTransaction();

            $salesOrder = SalesOrder::create([
                'sales_order_no' => $request->input('soNo1'),
                'sales_order_date' => $request->input('soDate'),
                'grn_no' => $request->input('grnNo1'),
                'customer_ref_no' => $request->input('custRefSoNo'),
                'company_name' => $request->input('companyName'),
                'company_address' => $request->input('soCompanyAddress'),
                'company_gstn' => $request->input('soCompanyGSTN'),
                'company_phone' => $request->input('soCompanyPhone'),
                'company_email' => $request->input('soCompanyEmail'),
                'quotation_no' => $request->input('quotationNo2'),
                'quotation_date' => $request->input('quotationDate') ?: null,
                'rfq_no' => $request->input('rfqNo'),
                'rfq_date' => $request->input('rfqDate') ?: null,
                'part_no' => $request->input('partNo'),
                'project_material_no' => $request->input('projectMaterialNo'),
                'drawing_no' => $request->input('drawingId'),
                'drawing_rev' => $request->input('drawingRevision'),
                'description' => $request->input('projectDescription'),
                'bill_address' => $request->input('billAddress'),
                'ship_address' => $request->input('shipAddress'),
                'product_type' => $request->input('productType'),
                'inr_in_words' => $request->input('GT_in_letters'),
                'subtotal' => $request->input('totalAmount') ?: 0,
                'sgst_amount' => $request->input('sgstA') ?: 0,
                'cgst_amount' => $request->input('cgstA') ?: 0,
                'igst_amount' => $request->input('IgstA') ?: 0,
                'round_up' => $request->input('roundUp') ?: 0,
                'grand_total' => $request->input('grandTotal') ?: 0,
            ]);

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

            $items = $request->input('tableProducts');
            if (!is_array($items)) {
                throw new \Exception("Invalid items format received");
            }

            foreach ($items as $item) {
                $reqByDate = !empty($item['reqByDate']) ? $item['reqByDate'] : null;

                SalesOrderItem::create([
                    'sales_order_id' => $salesOrder->id,
                    'sl_no' => $item['slNo'] ?? null,
                    'material_code' => $item['materialCode'] ?? null,
                    'hsn_code' => $item['hsnCode'] ?? null,
                    'material_description' => $item['description'] ?? null,
                    'additional_details' => $item['additionalDetails'] ?? null,
                    'required_by_date' => $reqByDate,
                    'quantity' => $item['quantity'] ?? 0,
                    'uom' => $item['uom'] ?? null,
                    'unit_rate' => $item['unitRate'] ?? 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,
                ]);
            }

            Log::info('[SalesOrder] SalesOrderItems created');

            DB::commit();

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

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

    /**
     * Display the specified sales order
     */
    public function show(int $id)
    {
        $order = SalesOrder::with(['items', 'customer', 'quotation'])->findOrFail($id);
        return $this->roleView('sales.show', compact('order'));
    }

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

    /**
     * Display the edit form
     */
    public function edit(int $id)
    {
        $order = SalesOrder::with('items', 'quotation')->findOrFail($id);
        $customers = CustomerVendor::select('id', 'company')->get();
        $editOrderId = $id;

        return $this->roleView('sales.edit', compact('order', 'customers', 'editOrderId'));
    }

    /**
     * Update the specified sales order
     */
    public function update(Request $request, int $id): JsonResponse
    {
        try {
            $validated = $request->validate([
                'soNo1' => 'required|unique:sales_orders,sales_order_no,' . $id,
                'soDate' => 'required|date',
                'companyName' => 'required',
                'grandTotal' => 'required|numeric',
                'customerSO' => 'nullable|file|mimes:pdf,jpg,jpeg,png,doc,docx|max:10240',
            ]);

            DB::beginTransaction();

            $salesOrder = SalesOrder::findOrFail($id);
            $salesOrder->update([
                'sales_order_no' => $request->input('soNo1'),
                'sales_order_date' => $request->input('soDate'),
                'grn_no' => $request->input('grnNo1'),
                'customer_ref_no' => $request->input('custRefSoNo'),
                'company_name' => $request->input('companyName'),
                'company_address' => $request->input('soCompanyAddress'),
                'company_gstn' => $request->input('soCompanyGSTN'),
                'company_phone' => $request->input('soCompanyPhone'),
                'company_email' => $request->input('soCompanyEmail'),
                'quotation_no' => $request->input('quotationId'),
                'quotation_date' => $request->input('quotationDate') ?: null,
                'rfq_no' => $request->input('rfqNo'),
                'rfq_date' => $request->input('rfqDate') ?: null,
                'part_no' => $request->input('partNo'),
                'project_material_no' => $request->input('projectMaterialNo'),
                'drawing_no' => $request->input('drawingId'),
                'drawing_rev' => $request->input('drawingRevision'),
                'description' => $request->input('projectDescription'),
                'bill_address' => $request->input('billAddress'),
                'ship_address' => $request->input('shipAddress'),
                'product_type' => $request->input('productType'),
                'inr_in_words' => $request->input('GT_in_letters'),
                'subtotal' => $request->input('totalAmount') ?: 0,
                'sgst_amount' => $request->input('sgstA') ?: 0,
                'cgst_amount' => $request->input('cgstA') ?: 0,
                'igst_amount' => $request->input('IgstA') ?: 0,
                'round_up' => $request->input('roundUp') ?: 0,
                'grand_total' => $request->input('grandTotal') ?: 0,
            ]);

            if ($request->hasFile('customerSO')) {
                $path = $request->file('customerSO')->store('customer_sos', 'public');
                $salesOrder->update(['customer_so_path' => $path]);
            }

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

            $items = $request->input('tableProducts');
            if (!is_array($items)) {
                $items = json_decode($items, true);
            }
            if (!is_array($items)) {
                throw new \Exception("Invalid items format received");
            }

            foreach ($items as $item) {
                $reqByDate = !empty($item['reqByDate']) ? $item['reqByDate'] : null;

                SalesOrderItem::create([
                    'sales_order_id' => $salesOrder->id,
                    'sl_no' => $item['slNo'] ?? null,
                    'material_code' => $item['materialCode'] ?? null,
                    'hsn_code' => $item['hsnCode'] ?? null,
                    'material_description' => $item['description'] ?? null,
                    'additional_details' => $item['additionalDetails'] ?? null,
                    'required_by_date' => $reqByDate,
                    'quantity' => $item['quantity'] ?? 0,
                    'uom' => $item['uom'] ?? null,
                    'unit_rate' => $item['unitRate'] ?? 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' => 'Sales Order updated successfully!',
                'id' => $salesOrder->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();
            return response()->json(['error' => 'Server error occurred', 'message' => $e->getMessage()], 500);
        }
    }

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

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

            // Prevent deletion of approved orders (except by SuperAdmin)
            if ($order->status === 'approved' && !$this->isSuperAdmin()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot delete approved sales orders. Contact SuperAdmin.',
                ], 403);
            }

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

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

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

        $order = SalesOrder::findOrFail($id);
        $order->status = 'approved';
        $order->save();

        return response()->json(['success' => true, 'message' => 'Sales Order approved!']);
    }

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

        $order = SalesOrder::findOrFail($id);
        $order->status = 'rejected';
        $order->save();

        return response()->json(['success' => true, 'message' => 'Sales Order rejected!']);
    }

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