<?php

namespace App\Http\Controllers\Modules\Manufacturing;

use Carbon\Carbon;
use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Models\SkuMaster as Sku;
use App\Models\SkuApproval;
use App\Models\SkuMovement;
use App\Models\CustomerVendor;
use App\Models\Category;
use App\Models\StockItem;
use App\Services\Manufacturing\SkuService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log;

/**
 * Unified SKU Controller
 *
 * Handles SKU (Stock Keeping Unit) management for all roles.
 * Reference: SuperAdminSKUController
 */
class SkuController extends Controller
{
    use HasRoleViews;

    protected SkuService $skuService;

    public function __construct(SkuService $skuService)
    {
        $this->skuService = $skuService;
    }

    // ==================== SKU Master ====================


    /**
     * Display the SKU master page
     */
    public function index()
    {
        // Get all categories ordered by name
        $categories = Category::orderByName()->get();

        // Get all active stock items ordered by name
        $items = StockItem::active()->orderByName()->get();

        return $this->roleView('sku.skumaster', compact('categories', 'items'));
    }

    /**
     * Alias for index - backward compatibility
     */
    public function skuMaster()
    {
        return $this->index();
    }

    /**
     * Get SKU data for DataTable (AJAX)
     */
    public function skuData(): JsonResponse
    {
        $skus = Sku::with(['stockItem.category'])->get();

        $data = [];

        foreach ($skus as $i => $sku) {

            $isLowStock = $sku->current_stock < $sku->min_order_level;

            $itemName = $sku->stockItem->item_name ?? '-';
            $category = $sku->stockItem->category->name ?? '-';

            $data[] = [
                'slno' => $i + 1,

                'item_name' => $itemName,

                'category' => $category,

                'uom' => $sku->uom,

                'current_stock' => $isLowStock
                    ? "<span class='text-danger font-weight-bold'>" . (int)$sku->current_stock . " <i class='fas fa-exclamation-triangle'></i></span>"
                    : (int)$sku->current_stock,

                'default_price' => $sku->default_price,

                'stock_status' => $sku->current_stock > 0
                    ? "<span class='badge badge-success'>In Stock</span>"
                    : "<span class='badge badge-danger'>Out of Stock</span>",

                'min_order_level' => $sku->min_order_level,

                'max_order_level' => $sku->max_order_level,

                'actions' => view($this->resolveView('sku.partials.actions'), compact('sku'))->render(),

                'DT_RowClass' => $isLowStock ? 'table-warning' : '',
            ];
        }

        return response()->json(['data' => $data]);
    }

    /**
     * Store a newly created SKU
     */
    public function store(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'stock_item_id' => 'required|string|max:255',
            'category_id' => 'required|string|max:255',
            'uom' => 'required|string|max:255',
            'tax_rate' => 'required|numeric',
            'current_stock' => 'required|integer',
            'default_price' => 'required|numeric',
            'min_order_level' => 'required|integer',
            'max_order_level' => 'required|integer',
        ]);

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

        Sku::create($request->all());

        return response()->json(['success' => 'SKU added successfully!']);
    }

    /**
     * Get SKU for editing (AJAX)
     */
    public function edit(int $id): JsonResponse
    {
        $sku = Sku::findOrFail($id);
        return response()->json($sku);
    }

    /**
     * Update the specified SKU
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $sku = Sku::findOrFail($id);

        $validator = Validator::make($request->all(), [
            'stock_item_id' => 'required|string|max:255',
            'category_id' => 'required|string|max:255',
            'uom' => 'required|string|max:255',
            'tax_rate' => 'required|numeric',
            'current_stock' => 'required|integer',
            'default_price' => 'required|numeric',
            'min_order_level' => 'required|integer',
            'max_order_level' => 'required|integer',
        ]);

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

        $sku->update($request->all());

        return response()->json(['success' => 'SKU updated successfully!']);
    }

    /**
     * Remove the specified SKU
     */
    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 and Manager can delete SKUs.'
            ], 403);
        }

        $sku = Sku::findOrFail($id);

        // Check if SKU has movements
        if ($sku->movements()->count() > 0 && !$this->isSuperAdmin()) {
            return response()->json([
                'success' => false,
                'message' => 'Cannot delete SKU with existing movements. Contact SuperAdmin.'
            ], 403);
        }

        $sku->delete();

        return response()->json(['success' => true, 'message' => 'SKU deleted successfully!']);
    }
    public function getItem($id)
    {
        $item = StockItem::with('category')->findOrFail($id);

        return response()->json([
            'category_id' => $item->category_id,
            'uom' => $item->uom,
            'hsn_code' => $item->hsn_code,
        ]);
    }

    // ==================== SKU APPROVAL ====================

    /**
     * Display the SKU approval page
     */
    public function skuApproval()
    {
        $customers = CustomerVendor::where('company_role', '!=', 'Vendor')->pluck('company', 'id');
        $items = StockItem::active()->orderByName()->get();

        return $this->roleView('sku.skuapproval', compact('customers', 'items'));
    }

    /**
     * Get SKU approval list for DataTable (AJAX)
     */
    public function skuApprovalList(): JsonResponse
    {
        // Get all approvals with customers
        $approvals = SkuApproval::with('customer')->orderBy('id', 'desc')->get();

        // Map StockItem ID => name
        $allSkus = StockItem::active()->orderByName()->pluck('item_name', 'id')->toArray();

        $data = [];
 
        foreach ($approvals as $approval) {
            $itemIds = is_array($approval->items) ? $approval->items : [];
            $itemNames = [];

            foreach ($itemIds as $id) {
                $id = (int) $id;
                if (isset($allSkus[$id])) {
                    $itemNames[] = $allSkus[$id];
                }
            }

            // Map stock status to user-friendly label
            $stockLabels = [
                'available' => 'In Stock',
                'partial' => 'Low Stock',
                'unavailable' => 'Out of Stock',
                'pre_order' => 'Pre-order',
            ];

            $data[] = [
                'id' => $approval->id,
                'customer' => $approval->customer?->company ?? '',
                'items' => implode(', ', $itemNames),
                'date' => $approval->date?->format('d-m-Y') ?? '',
                'approved_date' => $approval->approved_date?->format('d-m-Y') ?? '',
                'status' => $approval->status,
                'action_date' => $approval->action_date?->format('d-m-Y') ?? '',
                'action_by' => $approval->action_by ?? '-',
                'created_by' => $approval->created_by ?? '-',
                'stock_status' => $stockLabels[$approval->stock_status] ?? '-',
            ];
        }

        return response()->json(['data' => $data]);
    }

    /**
     * Store a new SKU approval
     */
    public function skuApprovalStore(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'customer' => 'required|integer',
            'items' => 'required|array|min:1',
            'date' => 'required|date',
            'approved_date' => 'nullable|date',
            'status' => 'required|string|max:50',
            'action_date' => 'nullable|date',
            'action_by' => 'nullable|string|max:255',
            'created_by' => 'required|string|max:255',
            'stock_status' => 'required|string|max:50',
        ]);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }

        $data = $request->all();

        // Map customer field
        $data['customer_id'] = $data['customer'];
        unset($data['customer']);

        // Ensure items stored as array
        $data['items'] = is_array($data['items']) ? $data['items'] : explode(',', $data['items']);

        // Map stock status to DB values
        $stockMap = [
            'In Stock' => SkuApproval::STOCK_STATUS_AVAILABLE,
            'Low Stock' => SkuApproval::STOCK_STATUS_PARTIAL,
            'Out of Stock' => SkuApproval::STOCK_STATUS_UNAVAILABLE,
            'Pre-order' => 'pre_order',
        ];
        $data['stock_status'] = $stockMap[$data['stock_status']] ?? SkuApproval::STOCK_STATUS_AVAILABLE;

        SkuApproval::create($data);

        return response()->json(['success' => true]);
    }

    /**
     * Get SKU approval for editing (AJAX)
     */
    public function skuApprovalShow(int $id): JsonResponse
    {
        $approval = SkuApproval::with('customer')->findOrFail($id);

        // Ensure items are array of IDs for Select2
        $items = is_array($approval->items) ? array_map('strval', $approval->items) : [];

        return response()->json([
            'id' => $approval->id,
            'customer_id' => $approval->customer_id,
            'customer_name' => $approval->customer?->company ?? '',
            'items' => $items,
            'date' => $approval->date?->format('Y-m-d') ?? '',
            'approved_date' => $approval->approved_date?->format('Y-m-d') ?? '',
            'status' => $approval->status,
            'action_date' => $approval->action_date?->format('Y-m-d') ?? '',
            'action_by' => $approval->action_by ?? '',
            'created_by' => $approval->created_by ?? '',
            'stock_status' => match($approval->stock_status) {
                SkuApproval::STOCK_STATUS_AVAILABLE => 'In Stock',
                SkuApproval::STOCK_STATUS_PARTIAL => 'Low Stock',
                SkuApproval::STOCK_STATUS_UNAVAILABLE => 'Out of Stock',
                'pre_order' => 'Pre-order',
                default => '',
            },
        ]);
    }

    /**
     * Update SKU approval
     */
    public function skuApprovalUpdate(Request $request, int $id): JsonResponse
    {
        $approval = SkuApproval::findOrFail($id);

        $validator = Validator::make($request->all(), [
            'customer' => 'required|integer',
            'items' => 'required|array|min:1',
            'date' => 'required|date',
            'approved_date' => 'nullable|date',
            'status' => 'required|string|max:50',
            'action_date' => 'nullable|date',
            'action_by' => 'nullable|string|max:255',
            'created_by' => 'required|string|max:255',
            'stock_status' => 'required|string|max:50',
        ]);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }

        $data = $request->all();

        // Map customer field
        $data['customer_id'] = $data['customer'];
        unset($data['customer']);

        // Ensure items stored as array
        $data['items'] = is_array($data['items']) ? $data['items'] : explode(',', $data['items']);

        // Map stock status to DB values
        $stockMap = [
            'In Stock' => SkuApproval::STOCK_STATUS_AVAILABLE,
            'Low Stock' => SkuApproval::STOCK_STATUS_PARTIAL,
            'Out of Stock' => SkuApproval::STOCK_STATUS_UNAVAILABLE,
            'Pre-order' => 'pre_order',
        ];
        $data['stock_status'] = $stockMap[$data['stock_status']] ?? SkuApproval::STOCK_STATUS_AVAILABLE;

        $approval->update($data);

        return response()->json(['success' => true]);
    }

    /**
     * Delete SKU approval
     */
    public function skuApprovalDestroy(int $id): JsonResponse
    {
        $approval = SkuApproval::findOrFail($id);
        $approval->delete();
        return response()->json(['success' => true]);
    }

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

        $approval = SkuApproval::findOrFail($id);
        $approval->status = 'approved';
        $approval->approved_date = now();
        $approval->action_by = auth()->user()->name ?? 'SuperAdmin';
        $approval->action_date = now();
        $approval->save();

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

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

        $approval = SkuApproval::findOrFail($id);
        $approval->status = 'rejected';
        $approval->action_by = auth()->user()->name ?? 'SuperAdmin';
        $approval->action_date = now();
        $approval->save();

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

    // ==================== SKU MOVEMENT ====================

    /**
     * Display the SKU movement page
     */
    public function skuMovement()
    {
        $items = StockItem::active()->orderByName()->get();
        $skus = Sku::orderBy('stock_item_id')->get();
        $stockitems = StockItem::active()->orderByName()->get();

        // Get unique locations from existing movements, plus default locations
        $existingLocations = SkuMovement::pluck('from_location')
            ->merge(SkuMovement::pluck('to_location'))
            ->filter()
            ->unique()
            ->values()
            ->toArray();

        $defaultLocations = ['Warehouse', 'Production', 'Inventory', 'Shipping', 'Receiving'];
        $locations = collect(array_merge($defaultLocations, $existingLocations))->unique()->sort()->values();

        return $this->roleView('sku.skumovement', compact('items', 'skus', 'locations', 'stockitems'));
    }

    /**
     * Get SKU movement list (AJAX)
     */
    public function skuMovementList(): JsonResponse
    {
        $movements = SkuMovement::with('sku')->orderBy('id', 'desc')->get();

        // Get all active stock items ordered by name
        $items = StockItem::active()->orderByName()->get();

        $data = [];
        foreach ($movements as $movement) {
            $data[] = [
                'id' => $movement->id,
                'reference' => $movement->reference ?? $movement->reference_no ?? '-',
                'item_name' => $movement->sku_id
                    ? $items->where('id', $movement->sku_id)->value('item_name')
                    : ($movement->product ?? ''),
                'type' => $movement->type ?? $movement->movement_type ?? 'inbound',
                'quantity' => $movement->quantity ?? 0,
                'from_location' => $movement->from_location ?? '',
                'to_location' => $movement->to_location ?? '',
                'date' => $movement->date ? $movement->date->format('d-M-Y') : '',
                'status' => $movement->status ?? 'completed',
                'notes' => $movement->notes ?? $movement->remarks ?? '',
            ];
        }

        return response()->json(['data' => $data]);
    }

    public function skuMovementStore(Request $request)
    {
        $data = $request->validate([
            'reference' => 'required' . $request->id,
            'sku_id' => 'required|exists:skumaster,stock_item_id',
            'type' => 'required',
            'quantity' => 'required|integer|min:1',
            'date' => 'required|date',
            'status' => 'required',
            'from_location' => 'nullable|string',
            'to_location' => 'nullable|string',
            'notes' => 'nullable|string'
        ]);

        $sku = Sku::where('stock_item_id', $request->sku_id)->firstOrFail();

        $quantity = (int)$request->quantity;
        $type = strtolower($request->type);

        if(in_array($type,['outbound','transfer']) && $quantity > $sku->current_stock){

            return response()->json([
                'success'=>false,
                'message'=>"Only {$sku->current_stock} items available. Cannot move {$quantity}."
            ],422);

        }

        if ($request->id) {

            $movement = SkuMovement::findOrFail($request->id);

            if($movement->type == 'inbound'){
                $sku->current_stock -= $movement->quantity;
            }

            if($movement->type == 'outbound'){
                $sku->current_stock += $movement->quantity;
            }

            $movement->update($data);

        } else {

            $movement = SkuMovement::create($data);

        }

        switch($type){

            case 'inbound':
                $sku->current_stock += $quantity;
            break;

            case 'outbound':
                $sku->current_stock -= $quantity;
            break;

            case 'adjustment':
                $sku->current_stock = $quantity;
            break;

        }

        $sku->save();

        return response()->json([
            'success'=>true,
            'message'=>'Movement saved',
            'new_stock'=>$sku->current_stock
        ]);
    }


    public function skuMovementShow($id)
    {
        $movement = SkuMovement::findOrFail($id);

        return response()->json([
            'id' => $movement->id,
            'reference' => $movement->reference,
            'sku_id' => $movement->sku_id,
            'quantity' => (int) $movement->quantity,
            'from_location' => $movement->from_location,
            'to_location' => $movement->to_location,
            // Only date, no time
            'date' => $movement->date ? $movement->date->format('Y-m-d') : null,
            'type' => $movement->type,
            'status' => $movement->status,
            'notes' => $movement->notes,
        ]);
    }

    public function skuMovementDelete($id)
    {
        $movement = SkuMovement::findOrFail($id);
        $movement->delete();

        return response()->json([
            'success' => true,
            'message' => 'Movement deleted'
        ]);
    }
}
