<?php

namespace Modules\Inventory\Controllers;

use core\Controller;
use core\Auth;
use core\Database;
use core\Session;
use Modules\Inventory\Models\Product;

class ProductController extends Controller
{
    private Product $productModel;

    public function __construct()
    {
        parent::__construct();
        $this->productModel = new Product();
    }

    public function index(): void
    {
        $this->requirePermission('inventory_view');

        $search = $this->request->get('search', '');
        $categoryId = $this->request->get('category_id', '');
        $supplierId = $this->request->get('supplier_id', '');
        $status = $this->request->get('status', '');
        $page = max(1, (int)$this->request->get('page', 1));
        $perPage = PAGINATION_LIMIT;
        $db = Database::getInstance();

        $query = $db->table('products p')
            ->select('p.*, c.name as category_name, s.name as supplier_name')
            ->leftJoin('product_categories c', 'p.category_id', '=', 'c.id')
            ->leftJoin('suppliers s', 'p.supplier_id', '=', 's.id')
            ->where('p.deleted_at', 'IS', null);

        if (!empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('p.name', 'LIKE', '%' . $search . '%')
                  ->orWhere('p.sku', 'LIKE', '%' . $search . '%')
                  ->orWhere('p.barcode', 'LIKE', '%' . $search . '%');
            });
        }

        if (!empty($categoryId)) {
            $query->where('p.category_id', $categoryId);
        }

        if (!empty($supplierId)) {
            $query->where('p.supplier_id', $supplierId);
        }

        if ($status === 'active') {
            $query->where('p.is_active', 1);
        } elseif ($status === 'inactive') {
            $query->where('p.is_active', 0);
        } elseif ($status === 'low_stock') {
            $query->where('p.current_stock', '<=', $db->raw('p.reorder_level'));
        }

        $products = $query->orderBy('p.name', 'ASC')
            ->paginate($perPage, $page);

        $categories = $db->table('product_categories')
            ->where('deleted_at', 'IS', null)
            ->orderBy('name', 'ASC')
            ->get();

        $suppliers = $db->table('suppliers')
            ->where('deleted_at', 'IS', null)
            ->where('is_active', 1)
            ->orderBy('name', 'ASC')
            ->get();

        $this->view('Inventory/index', [
            'title' => 'Products',
            'breadcrumb' => ['Inventory' => url('inventory')],
            'products' => $products,
            'search' => $search,
            'categoryId' => $categoryId,
            'supplierId' => $supplierId,
            'status' => $status,
            'categories' => $categories,
            'suppliers' => $suppliers,
        ]);
    }

    public function create(): void
    {
        $this->requirePermission('inventory_create');

        $db = Database::getInstance();
        $categories = $db->table('product_categories')
            ->where('deleted_at', 'IS', null)
            ->orderBy('name', 'ASC')
            ->get();

        $suppliers = $db->table('suppliers')
            ->where('deleted_at', 'IS', null)
            ->where('is_active', 1)
            ->orderBy('name', 'ASC')
            ->get();

        $this->view('Inventory/create', [
            'title' => 'Add New Product',
            'breadcrumb' => [
                'Inventory' => url('inventory'),
                'Add New' => url('inventory/create'),
            ],
            'categories' => $categories,
            'suppliers' => $suppliers,
        ]);
    }

    public function store(): void
    {
        $this->requirePermission('inventory_create');

        $validated = $this->validate([
            'name' => 'required|max_length:255',
            'sku' => 'max_length:100',
            'barcode' => 'max_length:100',
            'category_id' => 'required|integer',
            'supplier_id' => 'integer',
            'description' => 'max_length:2000',
            'unit_price' => 'numeric|min:0',
            'cost_price' => 'numeric|min:0',
            'tax_percent' => 'numeric|min:0|max:100',
            'reorder_level' => 'integer|min:0',
            'current_stock' => 'integer|min:0',
            'min_stock' => 'integer|min:0',
            'max_stock' => 'integer|min:0',
            'unit_type' => 'max_length:50',
            'track_inventory' => 'in:0,1',
            'is_active' => 'in:0,1',
        ]);

        if (empty($validated['sku'])) {
            $validated['sku'] = 'PRD-' . strtoupper(substr(uniqid(), -8));
        }

        $db = Database::getInstance();

        if ($db->table('products')->where('name', $validated['name'])->where('deleted_at', 'IS', null)->first()) {
            $this->response->withInput()->withAlert('error', 'A product with this name already exists.')->redirect(url('inventory/create'));
        }

        if ($db->table('products')->where('sku', $validated['sku'])->where('deleted_at', 'IS', null)->first()) {
            $this->response->withInput()->withAlert('error', 'A product with this SKU already exists.')->redirect(url('inventory/create'));
        }

        $validated['track_inventory'] = $validated['track_inventory'] ?? 1;
        $validated['is_active'] = $validated['is_active'] ?? 1;
        $validated['current_stock'] = $validated['current_stock'] ?? 0;
        $validated['reorder_level'] = $validated['reorder_level'] ?? 0;

        if (empty($validated['supplier_id'])) {
            unset($validated['supplier_id']);
        }

        $productId = $this->productModel->create($validated);
        $this->logActivity('create', 'Created product: ' . ($validated['name'] ?? ''));
        $this->logAudit('create', 'products', $productId, null, $validated);

        $this->redirectWith(url('inventory'), 'success', 'Product created successfully.');
    }

    public function edit(int $id): void
    {
        $this->requirePermission('inventory_edit');

        $product = $this->productModel->find($id);
        if (!$product) {
            $this->redirectWith(url('inventory'), 'error', 'Product not found.');
        }

        $db = Database::getInstance();
        $categories = $db->table('product_categories')
            ->where('deleted_at', 'IS', null)
            ->orderBy('name', 'ASC')
            ->get();

        $suppliers = $db->table('suppliers')
            ->where('deleted_at', 'IS', null)
            ->where('is_active', 1)
            ->orderBy('name', 'ASC')
            ->get();

        $this->view('Inventory/edit', [
            'title' => 'Edit Product',
            'breadcrumb' => [
                'Inventory' => url('inventory'),
                'Edit' => url('inventory/edit/' . $id),
            ],
            'product' => $product,
            'categories' => $categories,
            'suppliers' => $suppliers,
        ]);
    }

    public function update(int $id): void
    {
        $this->requirePermission('inventory_edit');

        $product = $this->productModel->find($id);
        if (!$product) {
            $this->redirectWith(url('inventory'), 'error', 'Product not found.');
        }

        $oldValues = (array)$product;

        $validated = $this->validate([
            'name' => 'required|max_length:255',
            'sku' => 'max_length:100',
            'barcode' => 'max_length:100',
            'category_id' => 'required|integer',
            'supplier_id' => 'integer',
            'description' => 'max_length:2000',
            'unit_price' => 'numeric|min:0',
            'cost_price' => 'numeric|min:0',
            'tax_percent' => 'numeric|min:0|max:100',
            'reorder_level' => 'integer|min:0',
            'current_stock' => 'integer|min:0',
            'min_stock' => 'integer|min:0',
            'max_stock' => 'integer|min:0',
            'unit_type' => 'max_length:50',
            'track_inventory' => 'in:0,1',
            'is_active' => 'in:0,1',
        ]);

        $validated['track_inventory'] = $validated['track_inventory'] ?? 0;
        $validated['is_active'] = $validated['is_active'] ?? 0;

        $db = Database::getInstance();

        $existing = $db->table('products')->where('name', $validated['name'])->where('id', '!=', $id)->where('deleted_at', 'IS', null)->first();
        if ($existing) {
            $this->response->withInput()->withAlert('error', 'A product with this name already exists.')->redirect(url('inventory/edit/' . $id));
        }

        if (!empty($validated['sku'])) {
            $existing = $db->table('products')->where('sku', $validated['sku'])->where('id', '!=', $id)->where('deleted_at', 'IS', null)->first();
            if ($existing) {
                $this->response->withInput()->withAlert('error', 'A product with this SKU already exists.')->redirect(url('inventory/edit/' . $id));
            }
        }

        if (empty($validated['supplier_id'])) {
            $validated['supplier_id'] = null;
        }

        $this->productModel->update($id, $validated);
        $this->logActivity('update', 'Updated product: ' . ($validated['name'] ?? ''));
        $this->logAudit('update', 'products', $id, $oldValues, $validated);

        $this->redirectWith(url('inventory'), 'success', 'Product updated successfully.');
    }

    public function show(int $id): void
    {
        $this->requirePermission('inventory_view');

        $db = Database::getInstance();
        $product = $db->table('products p')
            ->select('p.*, c.name as category_name, s.name as supplier_name, 
                     s.contact_person as supplier_contact, s.email as supplier_email, s.phone as supplier_phone')
            ->leftJoin('product_categories c', 'p.category_id', '=', 'c.id')
            ->leftJoin('suppliers s', 'p.supplier_id', '=', 's.id')
            ->where('p.id', $id)
            ->where('p.deleted_at', 'IS', null)
            ->first();

        if (!$product) {
            $this->redirectWith(url('inventory'), 'error', 'Product not found.');
        }

        $stockMovements = $db->table('stock_movements sm')
            ->select('sm.*, u.first_name as user_first_name, u.last_name as user_last_name')
            ->leftJoin('users u', 'sm.created_by', '=', 'u.id')
            ->where('sm.product_id', $id)
            ->orderBy('sm.created_at', 'DESC')
            ->limit(50)
            ->get();

        $batches = $db->table('product_batches')
            ->where('product_id', $id)
            ->orderBy('expiry_date', 'ASC')
            ->get();

        $purchases = $db->table('purchase_order_items pi')
            ->select('pi.*, po.order_number, po.status, po.created_at as po_date, s.name as supplier_name')
            ->leftJoin('purchase_orders po', 'pi.purchase_order_id', '=', 'po.id')
            ->leftJoin('suppliers s', 'po.supplier_id', '=', 's.id')
            ->where('pi.product_id', $id)
            ->orderBy('po.created_at', 'DESC')
            ->limit(20)
            ->get();

        $this->view('Inventory/show', [
            'title' => $product->name,
            'breadcrumb' => [
                'Inventory' => url('inventory'),
                $product->name => url('inventory/show/' . $id),
            ],
            'product' => $product,
            'stockMovements' => $stockMovements,
            'batches' => $batches,
            'purchases' => $purchases,
        ]);
    }

    public function delete(int $id): void
    {
        $this->requirePermission('inventory_delete');

        $product = $this->productModel->find($id);
        if (!$product) {
            $this->redirectWith(url('inventory'), 'error', 'Product not found.');
        }

        $this->productModel->softDelete($id);
        $this->logActivity('delete', 'Deleted product: ' . $product->name);
        $this->logAudit('delete', 'products', $id, (array)$product, null);

        $this->redirectWith(url('inventory'), 'success', 'Product deleted successfully.');
    }

    public function search(): void
    {
        $this->requirePermission('inventory_view');

        $query = $this->request->get('q', '');
        $results = [];

        if (!empty($query)) {
            $results = $this->productModel->search($query);
        }

        $this->json([
            'success' => true,
            'data' => $results,
        ]);
    }

    public function lowStock(): void
    {
        $this->requirePermission('inventory_view');

        $db = Database::getInstance();
        $branchId = Auth::branchId();

        $products = $this->productModel->getLowStock($branchId);

        $this->view('Inventory/low_stock', [
            'title' => 'Low Stock Products',
            'breadcrumb' => [
                'Inventory' => url('inventory'),
                'Low Stock' => url('inventory/low-stock'),
            ],
            'products' => $products,
        ]);
    }

    public function expiring(): void
    {
        $this->requirePermission('inventory_view');

        $days = (int)$this->request->get('days', 30);
        $products = $this->productModel->getExpiring($days);

        $db = Database::getInstance();
        $products = $db->table('product_batches pb')
            ->select('pb.*, p.name as product_name, p.sku, p.unit_price, 
                     s.name as supplier_name')
            ->leftJoin('products p', 'pb.product_id', '=', 'p.id')
            ->leftJoin('suppliers s', 'p.supplier_id', '=', 's.id')
            ->where('pb.expiry_date', '<=', date('Y-m-d', strtotime('+' . $days . ' days')))
            ->where('pb.expiry_date', '>=', date('Y-m-d'))
            ->where('pb.quantity', '>', 0)
            ->where('p.deleted_at', 'IS', null)
            ->orderBy('pb.expiry_date', 'ASC')
            ->get();

        $this->view('Inventory/low_stock', [
            'title' => 'Expiring Products',
            'breadcrumb' => [
                'Inventory' => url('inventory'),
                'Expiring' => url('inventory/expiring'),
            ],
            'products' => $products,
            'days' => $days,
            'isExpiring' => true,
        ]);
    }

    public function batchStore(): void
    {
        $this->requirePermission('inventory_edit');

        $validated = $this->validate([
            'product_id' => 'required|integer',
            'batch_number' => 'required|max_length:50',
            'expiry_date' => 'required|date',
            'quantity' => 'required|integer|min:1',
            'cost_price' => 'numeric|min:0',
        ]);

        $db = Database::getInstance();

        try {
            $product = $db->table('products')->where('id', (int)$validated['product_id'])->first();
            if (!$product) {
                throw new \RuntimeException('Product not found.');
            }

            $existing = $db->table('product_batches')
                ->where('product_id', (int)$validated['product_id'])
                ->where('batch_number', $validated['batch_number'])
                ->first();

            if ($existing) {
                throw new \RuntimeException('Batch number already exists for this product.');
            }

            $db->table('product_batches')->insert([
                'product_id' => (int)$validated['product_id'],
                'batch_number' => $validated['batch_number'],
                'expiry_date' => $validated['expiry_date'],
                'quantity' => (int)$validated['quantity'],
                'cost_price' => (float)($validated['cost_price'] ?? 0),
                'received_date' => date('Y-m-d'),
            ]);

            $db->table('products')
                ->where('id', (int)$validated['product_id'])
                ->update(['current_stock' => $product->current_stock + (int)$validated['quantity']]);

            $db->table('stock_movements')->insert([
                'product_id' => (int)$validated['product_id'],
                'movement_type' => 'adjustment',
                'quantity' => (int)$validated['quantity'],
                'before_quantity' => $product->current_stock,
                'after_quantity' => $product->current_stock + (int)$validated['quantity'],
                'reference_type' => 'manual',
                'reference_id' => null,
                'created_by' => Auth::id(),
            ]);

            $this->logActivity('create', 'Added batch ' . $validated['batch_number'] . ' to product: ' . $product->name);
            $this->logAudit('create', 'product_batches', null, $validated, null);

            $this->response->withAlert('success', 'Batch added successfully.')
                ->redirect(url('inventory/show/' . $validated['product_id']));
        } catch (\RuntimeException $e) {
            $this->response->withAlert('error', $e->getMessage())
                ->redirect(url('inventory/show/' . $validated['product_id']));
        }
    }

    public function batchDispose(int $id): void
    {
        $this->requirePermission('inventory_edit');

        $db = Database::getInstance();

        try {
            $batch = $db->table('product_batches')->where('id', $id)->first();
            if (!$batch) {
                throw new \RuntimeException('Batch not found.');
            }
            if ($batch->quantity <= 0) {
                throw new \RuntimeException('Batch already has zero quantity.');
            }

            $product = $db->table('products')->where('id', $batch->product_id)->first();
            if (!$product) {
                throw new \RuntimeException('Product not found.');
            }

            $disposedQty = (int)$batch->quantity;

            $db->table('product_batches')
                ->where('id', $id)
                ->update(['quantity' => 0]);

            $newStock = max(0, $product->current_stock - $disposedQty);
            $db->table('products')
                ->where('id', $batch->product_id)
                ->update(['current_stock' => $newStock]);

            $db->table('stock_movements')->insert([
                'product_id' => $batch->product_id,
                'movement_type' => 'adjustment',
                'quantity' => $disposedQty,
                'before_quantity' => $product->current_stock,
                'after_quantity' => $newStock,
                'reference_type' => 'manual',
                'reference_id' => null,
                'created_by' => Auth::id(),
            ]);

            $this->logActivity('delete', 'Disposed batch ' . $batch->batch_number . ' of product: ' . $product->name);
            $this->logAudit('delete', 'product_batches', $id, (array)$batch, ['quantity' => 0]);

            $this->response->withAlert('success', 'Batch disposed (' . $disposedQty . ' units removed). Current stock: ' . $newStock)
                ->redirect(url('inventory/expiring'));
        } catch (\RuntimeException $e) {
            $this->response->withAlert('error', $e->getMessage())
                ->redirect(url('inventory/expiring'));
        }
    }
}
